EF Query getting the Include operation for navigation not reachable warning - c#

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; }
}

Related

How to properly map Entity Framework entities to DTO and vice-versa?

In the data access level, I have defined such an entity:
public class Instagram
{
public int Id { get; set; }
public string Username { get; set; } = null!;
public string Password { get; set; } = null!;
public string? StateData { get; set; }
public string? TwoFactorLoginInfo { get; set; }
public string? ChallengeLoginInfo { get; set; }
public bool IsActive { get; set; }
public bool IsSelected { get; set; }
public long UserId { get; set; }
public User User { get; set; } = null!;
public Proxy? Proxy { get; set; }
public int? ProxyId { get; set; }
public List<Work>? Works { get; set; }
}
At the abstraction level, there is such a DTO:
public class InstagramDto
{
public int Id { get; set; }
public string Username { get; set; } = null!;
public string Password { get; set; } = null!;
public string? StateData { get; set; }
public string? TwoFactorLoginInfo { get; set; }
public string? ChallengeLoginInfo { get; set; }
public bool IsSelected { get; set; }
public bool IsActive { get; set; }
public UserDto? User { get; set; }
public ProxyDto? Proxy { get; set; }
}
Did I form the DTO correctly? It maps well to one side (from EF to DTO), but the problem is reverse mapping. I do it like this:
CreateMap<InstagramDto, Instagram>()
.ForMember(x => x.UserId,
expression => expression.MapFrom((dto, _) => dto.User?.Id))
.ForMember(x => x.User, expression => expression.Ignore())
.ForMember(x => x.Proxy,
expression => expression.MapFrom((dto, _) => dto.Proxy?.Id))
.ForMember(x => x.Proxy, expression => expression.Ignore());
CreateMap<Instagram, InstagramDto>();
That is, InstagramDto must have UserDTO and ProxyDto so that I can correctly map the entity from DTO to ef. At the same time, the user may have some other navigation properties that are not involved when receiving Instagram. This means that I cannot update the User, as its navigation properties are not loaded in this situation. Is this the right approach or would it be better to do so:
public int Id { get; set; }
public string Username { get; set; } = null!;
public string Password { get; set; } = null!;
public string? StateData { get; set; }
public string? TwoFactorLoginInfo { get; set; }
public string? ChallengeLoginInfo { get; set; }
public bool IsSelected { get; set; }
public bool IsActive { get; set; }
public long UserId { get; set; }
public int ProxyId { get; set; }

Entity Framework Core - Finding data in another table using a lambda function

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();

Invalid column name: "ColumnName#" with a suffix number

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?

Automapper many to many mapping confusion

I have many to many relationship tables such as "User & Notification & UserNotification" and their entities, view models also.
There is only a difference between ViewModel and Entity classes. HasRead property is inside NotificationViewModel. How Can I map this entities to view models? I could not achieve this for HasRead property.
What I did so far is,
Mapping Configuration:
CreateMap<Notification, NotificationViewModel>();
CreateMap<User, UserViewModel>().ForMember(dest => dest.Notifications, map => map.MapFrom(src => src.UserNotification.Select(x => x.Notification)));
Notification class:
public class Notification : IEntityBase
{
public Notification()
{
this.UserNotification = new HashSet<UserNotification>();
}
public int Id { get; set; }
public string Header { get; set; }
public string Content { get; set; }
public System.DateTime CreateTime { get; set; }
public bool Status { get; set; }
public virtual ICollection<UserNotification> UserNotification { get; set; }
}
User Class
public class User : IEntityBase
{
public User()
{
this.UserNotification = new HashSet<UserNotification>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public bool Status { get; set; }
public virtual ICollection<UserNotification> UserNotification { get; set; }
}
UserNotification class:
public class UserNotification : IEntityBase
{
public int Id { get; set; }
public int UserId { get; set; }
public int NotificationId { get; set; }
public bool HasRead { get; set; }
public virtual Notification Notification { get; set; }
public virtual User User { get; set; }
}
UserViewModel class
public class UserViewModel : IValidatableObject
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public bool Status { get; set; }
public IList<NotificationViewModel> Notifications { get; set; }
}
NotificationViewModel class
public class NotificationViewModel
{
public int Id { get; set; }
public string Header { get; set; }
public string Content { get; set; }
public System.DateTime CreateTime { get; set; }
public bool Status { get; set; }
public bool HasRead { get; set; } // this is the difference
}
In order to fix up the HasRead, maybe you can utilize the AfterMap(Action<TSource, TDestination> afterFunction) function. It's not as elegant as the rest of automapper, but it might work.
CreateMap<User, UserViewModel>()
.ForMember(dest => dest.Notifications, map => map.MapFrom(src => src.UserNotification.Select(x => x.Notification)))
.AfterMap((src, dest) =>
{
foreach (var notificationVM in dest.Notifications)
{
notificationVM.HasRead = src.UserNotification.Where(x => x.NotificationId == notificationVM.Id).Select(x => x.HasRead).FirstOrDefault();
}
});

EF 4.2 Many to many bug?

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.

Categories