How to avoid a relation-property to include its own relation? - c#

public class User
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public string Id { get; set; }
public string Username { get; set; }
public byte[] PasswordHash { get; set; }
public byte[] PasswordSalt { get; set; }
public string Role { get; set; }
public Organization Organization { get; set; }
}
public class Organization
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public string Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public int Phone { get; set; }
public string AccessToken { get; set; }
[ForeignKey("User")]
public string UserId { get; set; }
public User User { get; set; }
}
I have the following two tables created with EF code first.
I need to retrieve my User with Org but I don't want Org property to then again include the same User. How can I avoid that, so all I get is the user with the org?
This is the line that's causing me trouble:
return await _context.Users.Include(x => x.Organization).FirstOrDefaultAsync(x => x.Id == id);

I need to retrieve my User with Org but I don't want Org property to then again include the same User.
Either remove the Organization.User navigation property or, if you just want to remove it from a serialized output, decorate the navigation property with JsonIgnore (or similar)

Related

FK collection returned by EF is null, but validation for duplicates, confirms thats, the collection has content

I'm trying to get a data of all the user drone's, but ef core returning empty collection.
public class User : AuditableEntity
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string UserData { get; set; }
public bool IsActive { get; set; }
public bool IsAdmin { get; set; }
public DateTime LastActivity { get; set; }
public IEnumerable<Drone> Drones { get; set; }
}
public class Drone : AuditableEntity
{
public Guid Id { get; set; }
public string CustomName { get; set; }
public string Model { get; set; }
public int Serial { get; set; }
public bool IsActive { get; set; }
public string DroneData { get; set; }
public virtual User User { get; set; }
}
and user.Drones always has null value and i can't get and show the data, but this line of validation code
if (user.Drones.Contains(drone))
return ("This drone has been alredy registred", false);
shows me that, the user.Drones contains values.
Why i should do, to get user.Drones collection?
Ef uses a lazy loading, to load child instances you have to use Include
var user = context.Users.Where (i=> i.Id==userId)
.Include(i=>i.Drones)
.FirstOrDefault();
//or if you want just drones
var userDrones=context.Users.Where (i=> i.Id==userId)
.Select(i=>i.Drones)
.FirstOrDefault();
but it is better to add a foreign key UserId to Drone explicitly
public class Drone : AuditableEntity
{
public Guid Id { get; set; }
.....
public Guid UserId { get; set; }
public virtual User User { get; set; }
}
and use this query
var userDrones=context.Drones.Where (i=> i.UserId==userId).ToList();

Finding a table based on foreign key

I have these two tables and the bridge between them:
public class User
{
[Required]
public string Email { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
public int Id { get; set; }
public ICollection<UserLocation> UserLocations { get; set; }
[Required]
public string Password { get; set; }
[Required]
public string Username { get; set; }
}
public class Location
{
[Required]
public int Id { get; set; }
[Required]
public string Name { get; set; }
public string Picture { get; set; }
public string PostCode { get; set; }
public string Region { get; set; }
public ICollection<UserLocation> UserLocations { get; set; }
}
public class UserLocation
{
public Location Location { get; set; }
public int LocationId { get; set; }
public User User { get; set; }
public int UserId { get; set; }
}
I need to create a method that takes as a parameter a search field and a user id, returns all locations realted to that user id and searches if the string is contained in any of the locations' props.
I am having issues returning the locations based on user id.
I tried _context.UserLocations.Include(ul=>ul.Location).Where(l=>l.UserId==userId)
but that didn't work since I got a syntax error when trying to use l.UserId.
I also tried the other way around, _context.Locations.Include(l=>l.UserLocations) but ran into the same issue.
I need to find a way to retrieve all locations related to the user. The search can be easily done using the Contains() method afterwards.
Try this
_context.UserLocations.Where(x => x.UserId == userId).Select(x => x.Location)

MVC5 Referencing Guid

I am creating a table such as this:
public class Team
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public string CaptainId { get; set; }
public string CoCaptainId { get; set; }
public string ContactDetails { get; set; }
}
Then I have a table such as this:
public class TeamMember
{
public string Id { get; set; }
public string Description { get; set; }
public string GameDisplayName { get; set; }
public DateTime Joined { get; set; }
public string TeamId { get; set; }
}
I have 2 questions that I do not understand around EF 6 and MVC5.
1) How do I reference my Id field in Team table. Do I set TeamId inside TeamMember as a string or as a Guid? I understand I will need to set the attribute [ForeignKey("Team")] however I still do not understand how to properly reference to it in the code because whenever I need to do any type of comparison, I always have to type .ToString() on the Guid to be able to get the value to compare against another string value.
2) My TeamMember also has an Id, and this Id references User in Identity framework. How should I reference that one, the Id is meant to be a foreign key that references the Id in User table, but I do not know how to properly reference that one either, is it string like I did it or is it Guid or something else?
EDIT:
public class Team
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public Guid CaptainId { get; set; }
public Guid CoCaptainId { get; set; }
}
public class TeamMember
{
public Guid MemberId { get; set; }
public string TeamId { get; set; }
public virtual Team Team { get; set; }
public virtual Member Member { get; set; }
}
public class Member : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string About { get; set; }
public string Alias { get; set; }
public string CustomUrl { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<Member> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
}
public class ApplicationDbContext : IdentityDbContext<Member>
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
public DbSet<Team> Teams { get; set; }
public DbSet<TeamMember> TeamMembers { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<IdentityUserClaim>().ToTable("MemberClaim");
modelBuilder.Entity<IdentityUserRole>().ToTable("MemberRole");
modelBuilder.Entity<IdentityUserLogin>().ToTable("MemberLogin");
modelBuilder.Entity<IdentityRole>().ToTable("Role");
modelBuilder.Entity<Member>().ToTable("Member");
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
Error that I get:
var user = new Member { UserName = model.Email, Email = model.Email, CustomUrl = model.CustomUrl, Alias = model.Alias};
var team = new Team {CaptainId = user.Id, Created = currentTime, IsSingleMember = true};
CaptainId = user.Id gives an error:
Cannot convert source type 'string' to target type 'System.Guid'
You should use the same type, which is Guid.
public Guid TeamId { get; set; }
Also, you need to keep a virtual Team property of Team type in your TeamMember model. Also typically int or long or Guid are the types used for primary key of a table. string might not be a good idea as you need to execute your custom code to generate a string which does not exist in the table.
This will generate the 2 tables with proper foreign key relationships.
public class Team
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public string CaptainId { get; set; }
public string CoCaptainId { get; set; }
public string ContactDetails { get; set; }
}
public class TeamMember
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public string Description { get; set; }
public string GameDisplayName { get; set; }
public DateTime Joined { get; set; }
public Guid TeamId { get; set; }
public virtual Team Team { set; get; }
}
You do not need to do a ToString() conversion now for comparison. You can do YourGuid1==YourGuid2 expression

ASP MVC Application User Null using User.Identity.GetUserId

Ok so I have a relationship between the ApplicationUser and QuestionResults, my models are as below, the userId nor the UserName is retrieved, but I really need the UserId setup as a foreignKey on the QuestionResults entity.
Any help is much appreciated the error that I am receiving is as below:
An exception of type 'System.NullReferenceException' occurred in STRA.dll but was not handled in user code
Additional information: Object reference not set to an instance of an object.
on these lines of code:
qr.User.Id = User.Identity.GetUserId();
qr.User.UserName = User.Identity.GetUserName();
Models
public class QuestionResult
{
public QuestionResult()
{
DateCreated = DateTime.Now;
DateModified = DateTime.Now;
}
public int Id { get; set; }
public DateTime? DateCreated { get; set; }
public DateTime? DateModified { get; set; }
public int QuestionScore { get; set; }
//navigation properties
public virtual ApplicationUser User { get; set; }
//public ICollection<CategoryResult> CategoryResult { get; set; }
//public virtual Category Category { get; set; }
[NotMapped]
public int CategoryId { get; set; }
public virtual Question Question { get; set; }
public int QuestionId { get; set; }
//public virtual Category Category { get; set; }
//public int CategoryId { get; set; }
}
public class ApplicationUser : IdentityUser
{
public string FirstName { get; set; }
public string Surname { get; set; }
public string Industry { get; set; }
public string GlobalRegion { get; set; }
public string CurrentSituation { get; set; }
public int SalesForceSize { get; set; }
public bool IsVerified { get; set; }
//navigation properties
public virtual ICollection<CategoryResult> CategoryResult { get; set; }
public virtual ICollection<QuestionResult> QuestionResult { get; set; }
//public virtual ICollection<Report> Report { get; set; }
//public virtual ICollection<SurveyResult> SurveyResult { get; set; }
public virtual Organisation Organisation { get; set; }
public int? OrganisationId { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
}
Your code is equivalent to this::
var user = qr.User;
user.Id = User.Identity.GetUserId();
If the QuestionResult was already linked to a User then you would not be changing which User is linked to the QuestionResult, you would be changing the Id of an existing User - and that is not allowed anyway.
But the QuestionResult is not already linked to a User. qr.User is null - so you get a null reference exception.
In general, life is much easier in Entity Framework if you add the foreign key to your model:
public class QuestionResult
{
public string UserId { get; set; }
public virtual ApplicationUser User { get; set; }
}
And now you can set the foreign key directly:
qr.UserId = User.Identity.GetUserId();
References:
Why does Entity Framework Reinsert Existing Objects into My Database?
Making Do with Absent Foreign Keys
So, do you wanna make foreing key for userid?
You can do like that:
public int UserRefID { get; set; }
[ForeignKey("UserRefID")]
public xxx UserID { get; set; } //data name like ApplicationUser
And this error appear coz you have some problem about models or data classes.
Set it as a string
Model:
public ApplicationUser User { get; set; }
public string UserId { get; set; }
Controller:
qr.UserId = User.Identity.GetUserId();
And worked perfectly, even created foreign keys, that easy. Thanks so much!

Getting a foreign key in a table

In my website, a user can add foreignExpressions to his account. The user model looks like this:
[Table("UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public List<ForeignExpression> learnedexpressions { get; set; }
}
Then in the controller I'd like to get the current user's stored expressions like this:
db.ForeignExpressions.Select(f => f.UserId == Membership.GetUser().ProviderUserKey);
However, ForeignExpression does not contain a UserId field, so there's no visible UserId for f. But the UserProfile has a collecion of ForeignExpressions, so I have a UserId field in the ForeignExpression table. I'm confused, how am I supposed to get the ForeignExpressions for my user?
Edit:
public class ForeignExpression
{
public int ID { get; set; }
public string expression { get; set; }
public string context { get; set; }
public string meaning { get; set; }
public DateTime dateAdded { get; set; }
}
int userID = Membership.GetUser().ProviderUserKey;
db.UserProfiles.Find(q => q.UserID == userID).LearnedExpressions.ToList();

Categories