We are using the ASP.NET membership to manager our user and I found a problem using Entity Framework 4.2
I have the table in db called Aspnet_Users and I Created My class as:
public class Aspnet_User
{
[Key]
public Guid ID { get; set; }
public Guid ApplicationID { get; set; }
public string UserName { get; set; }
public string LoweredUserName { get; set; }
public string MobileAlias { get; set; }
public bool IsAnonymous { get; set; }
public DateTime LastActivityDate { get; set; }
public virtual Aspnet_Membership Aspnet_Membership { get; set; }
public virtual Aspnet_Profile Aspnet_Profile { get; set; }
public virtual ICollection<Aspnet_Role> Aspnet_Roles { get; set; }
public virtual ICollection<Agent> Agents { get; set; }
}
My Entity Configuration:
public class Aspnet_UserConfiguration : EntityTypeConfiguration<Aspnet_User>
{
public Aspnet_UserConfiguration()
: base()
{
HasKey(p => p.ID);
Property(p => p.ID).HasColumnName("UserId").IsRequired();
Property(p => p.MobileAlias).IsOptional();
HasOptional(p => p.Aspnet_Profile).WithRequired();
HasOptional(p => p.Aspnet_Membership).WithRequired();
HasMany(p => p.Aspnet_Roles).WithMany(a => a.Aspnet_Users).Map(mc =>
{
mc.MapLeftKey("UserId");
mc.MapRightKey("RoleId");
ToTable("aspnet_UsersInRoles");
});
HasMany(p => p.Agents).WithMany(a => a.Aspnet_Users).Map(mc =>
{
mc.MapLeftKey("UserId");
mc.MapRightKey("AgentId");
ToTable("aspnet_UsersAgent");
});
ToTable("aspnet_Users");
}
And Finally my Agent table:
public class Agent
{
[Key]
public int ID { get; set; }
public string Title { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
public string ShortBio { get; set; }
public string ExtendedBio { get; set; }
public string Tel { get; set; }
public string Fax { get; set; }
public string Email { get; set; }
public string CompanyName { get; set; }
public string ImageURL { get; set; }
public string BranchName { get; set; }
public string UserPassword { get; set; }
public DateTime? LastLogin { get; set; }
public bool? Active { get; set; }
public bool ShowMap { get; set; }
public string BatchNoPrefix { get; set; }
public string FullName
{
get { return string.Format("{0} {1}", FirstName, Surname); }
}
public virtual AgentsAddress Address { get; set; }
public virtual ICollection<PaymentNotification> PaymentNotifications { get; set; }
public virtual ICollection<Authority> Authorities { get; set; }
public virtual ICollection<Aspnet_Users> Aspnet_Users { get; set; }
}
The problem is: When I try to select my Aspnet_User in the class Agent, I'm getting a error:
Invalid object name 'dbo.Aspnet_UserAgent'.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Data.SqlClient.SqlException: Invalid object name 'dbo.Aspnet_UserAgent'.
I figured out that this error occur because my classname is in singular: Aspnet_User instead of Aspnet_Users.
But if I created the relationship inside my Configuration(see class aspnet_UserConfiguration), the system should not try to get aspnet_UsersAgent? Why is it try to get dbo.ClassName1_ClassName2? Is It a bug?
Thank you in advance.
Related
I have two tables in my database:
Contact
ContactRoles
The join table is Contact_ContactRole.
I have defined them in code as
Contact.cs
ContactRoles.cs
Contact_ContactRole.cs
I have defined a virtual property as follows:
public class Contact
{
public Contact()
{
}
public int ID { get; set; }
public int ClientID { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string Mobile { get; set; }
public int IsDefault { get; set; }
public bool IsActive { get; set; }
public bool IsInvoiceEmail { get; set; }
public DateTime CreationDate { get; set; }
public bool IsSubConsultant { get; set; }
public string Notes { get; set; }
//[NotMapped]
public virtual ICollection<ContactRoles> ContactRoles { get; set; }
}
public class ContactRoles
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<Contact> Contacts { get; set; }
}
public class Contact_ContactRole
{
public int ContactID { get; set; }
public int ContactRoleID { get; set; }
//public Contact Contact { get; set; }
//public ContactRoles ContactRole { get; set; }
}
AuthContext.cs
protected override void OnModelCreating(ModelBuilder builder)
{
builder
.Entity<Contact>()
.ToTable("Contact");
builder
.Entity<Contact_ContactRole>()
.ToTable("Contact_ContactRole");
builder
.Entity<ContactRoles>()
.ToTable("ContactRoles");
builder.Entity<Contact>()
.HasMany(p => p.ContactRoles)
.WithMany(p => p.Contacts)
.UsingEntity(j => j.ToTable("Contact_ContactRole"));
builder
.Entity<Contact_ContactRole>()
.HasKey(ccr => new { ccr.ContactID, ccr.ContactRoleID });
}
I am getting an error:
Cannot use table 'Contact_ContactRole' for entity type 'Contact_ContactRole'
since it is being used for entity type
'ContactContactRoles (Dictionary<string, object>)' and potentially other
entity types, but there is no linking relationship. Add a foreign key
to 'Contact_ContactRole' on the primary key properties and pointing to the
primary key on another entity typed mapped to 'Contact_ContactRole'.'
If I comment the code:
builder.Entity<Contact>()
.HasMany(p => p.ContactRoles)
.WithMany(p => p.Contacts)
.UsingEntity(j => j.ToTable("Contact_ContactRole"));
I get the following error:
Invalid object name 'ContactContactRoles'.
at Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
Try this
public class Contact
{
public Contact()
{
}
public int ContactId { get; set; } //PK
public int ClientID { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string Mobile { get; set; }
public int IsDefault { get; set; }
public bool IsActive { get; set; }
public bool IsInvoiceEmail { get; set; }
public DateTime CreationDate { get; set; }
public bool IsSubConsultant { get; set; }
public string Notes { get; set; }
[ForeignKey("ContactId")]
public virtual ICollection<Contact_ContactRole> ContactContactRoles { get; set; }
}
public class ContactRoles
{
public int ContactRoleId { get; set; } //PK
public string Name { get; set; }
[ForeignKey("ContactRoleId")]
public virtual ICollection<Contact_ContactRole> ContactContactRoles { get; set; }
}
public class Contact_ContactRole
{
public int ContactId { get; set; }
public Contact Contact { get; set; }
public int ContactRoleId { get; set; }
public ContactRoles ContactRole { get; set; }
}
also I believe that Contact_ContactRole needs a Primary Key. Currently the data annotations in EF Core does not have the option of creating Composite Primary Key.
Hence, we may have to fall back to Fluent API to create the Composite Key.
modelBuilder.Entity<Contact_ContactRole>()
.HasKey(e => new { e.ContactId, e.ContactRoleId });
I have two tables. Account and Tenant. There are many accounts to a tenant and this has been configured in the DbContext as follows.
modelBuilder.Entity<Account>()
.HasOne(b => b.Tenant)
.WithMany(a => a.Accounts)
.OnDelete(DeleteBehavior.Cascade);
The Account POCO class is as follows.
public class Account : IEntityBase, IAuditedEntityBase
{
public int Id { get; set; }
public int AccountNo { get; set; }
public string? AccountName { get; set; }
public string? Title { get; set; }
public string? AccountFirstName { get; set; }
public string? AccountLastName { get; set; }
public string? MobilePhone { get; set; }
public string? Email { get; set; }
public string? Address1 { get; set; }
public string? Address2 { get; set; }
public string? PasswordHash { get; set; }
public bool AcceptTerms { get; set; }
public int RoleId { get; set; }
public virtual Role Role { get; set; }
public string? VerificationToken { get; set; }
public DateTime? Verified { get; set; }
public bool IsVerified => Verified.HasValue || PasswordReset.HasValue;
public string? ResetToken { get; set; }
public DateTime? ResetTokenExpires { get; set; }
public DateTime? PasswordReset { get; set; }
public List<RefreshToken>? RefreshTokens { get; set; }
public bool OwnsToken(string token)
{
return this.RefreshTokens?.Find(x => x.Token == token) != null;
}
// One tenant to many user accounts
public int TenantId { get; set; }
public virtual Tenant? Tenant { get; set; }
// One suburb to many User accounts
public int SuburbId { get; set; }
public virtual Suburb? Suburb { get; set; }
}
The Tenant POCO class is as follows:
public class Tenant : IEntityBase, IAuditedEntityBase
{
public Tenant()
{
Accounts = new List<Account>();
}
public int Id { get; set; }
public int TenantNo { get; set; }
public string Database { get; set; }
public string CompanyName { get; set; }
public string ABN { get; set; }
public string CompanyAccountEmail { get; set; }
public string ContactFirstName { get; set; }
public string ContactLastName { get; set; }
public string OfficePhone { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string BankName { get; set; }
public string BankBSB { get; set; }
public string BankAccount { get; set; }
public int SuburbId { get; set; }
public virtual Suburb Suburb { get; set; }
// Many users to one tenant
public virtual ICollection<Account> Accounts { get; }
}
N ogiven there are multiple accounts to a tenant or "many accounts to one tenant" how,
if I have the account ID, obtain the tenantId using a lambda function.
I tried to use the following but got lost.
await tenantsContext.Accounts.Include(x => x.Tenant).Where(x => x.Id == accountId).SingleOrDefaultAsync(x => new Tenant.. and lost it here..
Can someone show me and others how you would, given an accountId (which equates to the Id of the account table) and get the TenantId for that account..
You can get TenantId for account with given accountId using this:
await tenantsContext.Accounts
.Where(x => x.Id == accountId)
.Select(x => x.TenantId)
.SingleOrDefaultAsync();
I have a simple query
clients = _context.Clients
.Include(e => e.TrainerClients)
.Include(e => e.User)
.Where(e => e.TrainerClients.All(f => f.Status == UserStatus.Linked));
that returns:
but I get a warning message if executed as-is:
The Include operation for navigation '[e].User' is unnecessary and was ignored because the navigation is not reachable in the final query results.
However, if I comment out the Include(e => e.User) from the query, I don't get the warning, but I also don't get the User data.
So why am I getting this warning, and how can I refine my query to not get the warning?
UPDATE:
Client model:
public class Client : BaseModel
{
public string UserId { get; set; }
[ForeignKey(nameof(UserId))]
public ApplicationUser User { get; set; }
public DateTime LastPaidDate { get; set; }
public string CreditCardNumber { get; set; }
public ICollection<TrainerClient> TrainerClients { get; set; }
}
ApplicationUser:
public class ApplicationUser : IdentityUser
{
public bool Facebook { get; set; }
public string ProfilePicture { get; set; }
public string CountryCode { get; set; }
public string State { get; set; }
public string City { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual DateTime? LastLoginTime { get; set; }
public virtual DateTime? RegistrationDate { get; set; }
public string Address { get; set; }
public string ZipCode { get; set; }
public int StateId { get; set; }
//Properties Client used just for relation
public Client Client { get; set; }
public ProfileSetting ProfileSetting { get; set; }
}
TrainerClient:
public class TrainerClient : BaseModel
{
public int TrainerId { get; set; }
[ForeignKey(nameof(TrainerId))]
public Trainer Trainer { get; set; }
public int ClientId { get; set; }
[ForeignKey(nameof(ClientId))]
public Client Client { get; set; }
public Enum.UserStatus Status { get; set; }
public Enum.RequestType RequestType { get; set; }
public string RequestDate { get; set; }
}
I have problem when I try to migrate my model in EF Core 2.0.
public class Profile
{
[Key]
public Guid Id { get; set; }
public Guid UserId { get; set; }
public ExternalUser User { get; set; }
}
public class OrganizationCustomerProfile : Profile
{
public string CompanyName { get; set; }
public Address LegalAddress { get; set; }
public Address ActualAddress { get; set; }
public BusinessRequisites Requisites { get; set; }
public string President { get; set; }
public IEnumerable<ContactPerson> ContactPerson { get; set; }
}
public class PersonCustomerProfile : Profile
{
public FullName Person { get; set; }
public Address Address { get; set; }
public string PhoneNumber { get; set; }
}
public class ContactPerson
{
[Key]
public Guid Id { get; set; }
public FullName Person { get; set; }
public string Rank { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public Guid ProfileId { get; set; }
public Profile Profile { get; set; }
}
Here I want to add complex datatypes Address and BusinessRequisites, which are:
public class BusinessRequisites
{
public string OGRN { get; set; }
public string INN { get; set; }
public string KPPCode { get; set; }
public string SettlementAccount { get; set; }
public string RCBIC { get; set; }
public string CorrespondentAccount { get; set; }
public string BankName { get; set; }
}
public class Address
{
public string FullAddress { get; set; }
public float Latitude { get; set; }
public float Longtitude { get; set; }
}
Code which I use for TPH binding:
public DbSet<Profile> UserProfiles { get; set; }
public DbSet<ContactPerson> ContactPerson { get; set; }
public DbSet<OrganizationCustomerProfile> OrganizationCustomerProfile { get; set; }
...
modelBuilder.Entity<Profile>().HasKey(u => u.Id);
modelBuilder.Entity<OrganizationCustomerProfile>().OwnsOne(e => e.ActualAddress);
modelBuilder.Entity<OrganizationCustomerProfile>().OwnsOne(e => e.LegalAddress);
modelBuilder.Entity<OrganizationCustomerProfile>().OwnsOne(e => e.Requisites);
But when I try to make a migration, I get an error:
"Cannot use table 'UserProfiles' for entity type
'OrganizationCustomerProfile.ActualAddress#Address' since it has a
relationship to a derived entity type 'OrganizationCustomerProfile'.
Either point the relationship to the base type 'Profile' or map
'OrganizationCustomerProfile.ActualAddress#Address' to a different
table."
So, what the reason of this error? Is it not possible to create hierarchy inheritance in EF Core 2.0?
Thank you!
It seems like this isn't supported at the moment:
https://github.com/aspnet/EntityFrameworkCore/issues/9888
I have a table Users:
I am using Entity Framework 6 to make the type configuration
public class UsersMapping : EntityTypeConfiguration<Users>
{
public UsersMapping()
{
HasKey(t => t.UserID);
Property(t => t.UserID).IsRequired();
ToTable("Users", "dbo");
Property(t => t.Id).HasColumnName("UserID");
}
}
and this is the Users class:
public class Users : EntityBase
{
public int UserID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string UserName { get; set; }
public DateTime DateCreated { get; set; }
public byte[] Timestamp { get; set; }
public byte[] Password { get; set; }
public DateTime? DateActivated { get; set; }
public bool LockedOut { get; set; }
public string Address { get; set; }
public string City { get; set; }
public int? State { get; set; }
public string Zip { get; set; }
public string SecurityQuestion { get; set; }
public string SecurityAnswer { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public bool? ReportServiceAccount { get; set; }
public string CompanyName { get; set; }
public int? ILAC { get; set; }
public string BioFingerprint { get; set; }
public string Title { get; set; }
public string Squad { get; set; }
public byte[] SignatureFile { get; set; }
public byte? CETGroupID { get; set; }
public string TokenID { get; set; }
public int? Pin { get; set; }
public string RadioNr { get; set; }
}
public class EntityBase
{
public int Id { get; set; }
}
I am trying to set the Id field as primary because my repository pattern works using the field Id that is not present on this case in the table. But when I am trying to get the set of users I get this error:
The column name is invalid UserID1
The weird thing to me is the #1 that is at the end. What I am doing wrong?