ASP.NETCore - Friends System - mysql

I`m building an application where I try to make a friend system.
Now, I work with 2 tables for that.
1st: Default AspNetUsers where i store user information.
2nd: Friends Table as below:
public class AspNetFriends
{
public int ID { get; set; }
public string friendFrom { get; set; }
public string friendTo { get; set; }
public bool isConfirmed { get; set; }
}
In this table both "friendFrom" and "friendTo" is string type, and receiving the registered users ID.
What i want to achieve is that when i display this table on my view, i want to show the Username of the same UserID thats either in the "friendFrom" or "friendTo" column.

You need to change your class as followed (I didn't test this):
Default application user of asp.net core
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
namespace project.Models
{
// Add profile data for application users by adding properties to the ApplicationUser class
public class ApplicationUser : IdentityUser
{
}
}
Model
public class AspNetFriends
{
public int ID { get; set; }
public bool isConfirmed { get; set; }
public virtual ApplicationUser friendFrom { get; set; }
public virtual ApplicationUser friendTo { get; set; }
}
Now you can get to the getters and setters of the aspnet user
Controller
public async Task<IActionResult> Details(int id)
{
var query = from m in _dbContext.AspNetFriends
join ff in _dbContext.Users on
new { m.friendFrom.Id } equals new { Id = cu.Id }
join ft in _dbContext.Users on
new { m.friendTo.Id } equals new { Id = cu.Id }
where m.ID == id
select m;
return View(query.Single());
}
View
#model project.AspNetFriends
<p>
#model.friendFrom.UserName
</P>
#item.CreationUser.UserName

Related

EF Core 2 Stopping Circular Dependency on Many to Many Relationship

I am using the Sakila Sample Database from MySql on a MySql server. The Diagram looks as follows.
The important tables are the store, inventory and film tables. The is a many-to-many relationship between the tables and the linker table is the inventory table.
I scaffolded this Database in a new dotnetcore project using EFCore 2.
I am trying to get a list of stores and their list of films.
The Entities are defined as follows:
Store
public class Store
{
public Store()
{
Customer = new HashSet<Customer>();
Inventory = new HashSet<Inventory>();
Staff = new HashSet<Staff>();
}
public byte StoreId { get; set; }
public byte ManagerStaffId { get; set; }
public short AddressId { get; set; }
public DateTimeOffset LastUpdate { get; set; }
public Address Address { get; set; }
public Staff ManagerStaff { get; set; }
public ICollection<Customer> Customer { get; set; }
public ICollection<Inventory> Inventory { get; set; }
public ICollection<Staff> Staff { get; set; }
}
Inventory
public partial class Inventory
{
public Inventory()
{
Rental = new HashSet<Rental>();
}
public int InventoryId { get; set; }
public short FilmId { get; set; }
public byte StoreId { get; set; }
public DateTimeOffset LastUpdate { get; set; }
public Film Film { get; set; }
public Store Store { get; set; }
public ICollection<Rental> Rental { get; set; }
}
Film
public partial class Film
{
public Film()
{
FilmActor = new HashSet<FilmActor>();
FilmCategory = new HashSet<FilmCategory>();
Inventory = new HashSet<Inventory>();
}
public short FilmId { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public short? ReleaseYear { get; set; }
public byte LanguageId { get; set; }
public byte? OriginalLanguageId { get; set; }
public byte RentalDuration { get; set; }
public decimal RentalRate { get; set; }
public short? Length { get; set; }
public decimal ReplacementCost { get; set; }
public string Rating { get; set; }
public string SpecialFeatures { get; set; }
public DateTimeOffset LastUpdate { get; set; }
public Language Language { get; set;
public Language OriginalLanguage { get; set; }
public ICollection<FilmActor> FilmActor { get; set; }
public ICollection<FilmCategory> FilmCategory { get; set; }
public ICollection<Inventory> Inventory { get; set; }
}
My context looks as follows:
modelBuilder.Entity<Inventory>(entity =>
{
entity.ToTable("inventory", "sakila");
entity.HasIndex(e => e.FilmId)
.HasName("idx_fk_film_id");
entity.HasIndex(e => new { e.StoreId, e.FilmId })
.HasName("idx_store_id_film_id");
And lastly the repo looks as follows:
public IEnumerable<Store> GetStores()
{
return _context.Store.
Include(a => a.Inventory).
ToList();
}
Problem:
When I call this method from a Controller to get the list of stores I don´t get any json response on Postman. Yet if I debug into the list that is returned from the Controller I find the list of stores.
The problem is that the list contains:
store->inventory->film->store->inventory->film->store... Etc. Creating a circular dependency that fills up the allowed Process memory of the request.
Possible Solutions:
I think it has to do with the fact that on the Context both the Foreign Keys are defined as HasIndex instead of HasKey
entity.HasIndex(e => new { e.StoreId, e.FilmId })
.HasName("idx_store_id_film_id");
When I define it as HasKey then I get an Error:
'The relationship from 'Rental.Inventory' to 'Inventory.Rental' with
foreign key properties {'InventoryId' : int} cannot target the primary
key {'StoreId' : byte, 'FilmId' : short} because it is not compatible.
Configure a principal key or a set of compatible foreign key
properties for this relationship.'
To answer #hamzas comment, I did find a solution to this problem. I used EFCore to build the entities and the DBContext through scaffolding (DB First). As a best practice you should be using Models (Dtos) to represent the Data for the client. EFCore is very helpful in giving us the flexibility to access this M to N relationship however we want. This gives us the flexibility to represent this Data to the client however we want.
Whatever your use case might be. You have to convert the M to N relationship into an 1 to N model.
Use Case #1: You want to show all the movies for a specific store.
Solution
Step #1: You create a StoreDto (Model)
public class StoreDto
{
int StoreId { get; set; }
ICollection<FilmDto> Films { get; set; }
= new List<FilmDto> ();
}
Step #2: Create a FilmDto
public class FilmDto
{
int FilmId { get; set; }
int StoreId { get; set; }
string FilmName { get; set; }
}
Step #3: You provide a Mapping with auto mapper
public class MappingProfiles : Profile
{
public MappingProfiles()
{
CreateMap<Store, StoreDto>();
CreateMap<Film, FilmDto>();
}
}
Step #4: Query the data correctly, Unfortunately I don´t have this example anymore to test this code, so here is where you´ll have to experiment a bit
public Store GetFilmsForStore(byte StoreId)
{
return _context.Store.
Include(a => a.Inventory).
ThenInclude(i => i.Film)
ToList();
}
On the "Include" part you want to only get the Inventory entries where StoreId == Inverntory.StoreId and then Include the Films Object from the resulting list.
I hope you get the jist of it. You want to break up your m to n relationships and make them seem like 1 to m for your clients.

Populating a list using Foreign Key Values in MVC

I'm developing a prototype platform using MVC in which users can make a profile and use that profile to make text posts, like a social media site. I have the following two tables in my database:
Profiles
public partial class Profile
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Profile()
{
this.Posts = new HashSet<Post>();
}
public int Id { get; set; }
public string UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Country_ { get; set; }
public System.DateTime DoB { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Post> Posts { get; set; }
}
}
Posts
public partial class Post
{
public int Id { get; set; }
public string Text { get; set; }
public System.DateTime DATE { get; set; }
public int ProfileId { get; set; }
public virtual Profile Profile { get; set; }
}
}
In my ViewModel I have a list of Posts called PostList, which I want to populate with all of the Post records made by the user. So, I need to populate the list with all records where the ProfileId in Posts is equal to the Id of Profile, which is determined by whether or not the UserId in Profile is equal to the current user's Identity.
In short, I need:
Post List = Posts where ProfileId = Profiles.Id Where Profiles.UserId = CurrentUserId.
Any ideas? I've tried the following, but it's totally wrong:
var userId = User.Identity.GetUserId();
ViewModels.ProfileViewModel pVm = new ViewModels.ProfileViewModel();
pVm.PostList = db.Posts.Include(db.Profiles).Where(a => a.UserId == userId).ToList();
pVm.UserName = User.Identity.GetUserName();
return View(pVm);
You just walk the relationship in your query:
pVm.PostList = db.Posts.Where(a => a.Profile.UserId == userId);
It's unnecessary to use Include since Profile will automatically be joined to make the query.

How to create a Join using petapoco MVC4

I need to join 2 table using petapoco MVC4
my table cong shown below
[TableName("District")]
[PrimaryKey("nDistrictID")]
public class District
{
public int nDistrictID { get; set; }
public string cDistrictName { get; set; }
public bool bActive { get; set; }
public int nStateID { get; set; }
}
And state table
[PetaPoco.TableName("States")]
[PetaPoco.PrimaryKey("nStateID")]
public class States
{
public int nStateID { get; set; }
public string cStateName { get; set; }
}
I need a query in this form
select d.cDistrictName,s.cStateName, d.nStateID from District
d inner join States s on d.nStateID=s.nStateID
I am assuming you have already a dataContext which contains 2 DbSet of each classes. Regarding that you can use:
Regarding the result you expect, you can create a new class which matches with the result:
public class DistrictWithState
{
public string cDistrictName {get;set;}
public string cStateName {get; set;}
public int nStateId {get;set;}
}
Then in your Action:
var dataContext = new PetaPoco.Database("mysql");
var sql="select d.cDistrictName,s.cStateName, d.nStateID from District
d inner join States s on d.nStateID=s.nStateID";
var districts = db.Fetch<DistrictWithState>(sql);
return view(districts);
There is another solution using the dynamic keyword. But just start with that solution above. It should work. I hope it will help

EF Code First, Web API, Json serialization Many to Many

Having som major problem with many to many relation.
public class Team
{
public Team()
{
Users = new HashSet<User>();
}
public int Id { get; set; }
public string Name { get; set; }
public ICollection<User> Users { get; set; }
}
public class User
{
public User()
{
Teams = new HashSet<Team>();
}
public int Id { get; set; }
public string Username { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string Cell { get; set; }
public ICollection<Team> Teams { get; set; }
}
After Returning a newly added Team like this
var currentUser = _ctx.Users.Where(u => u.Username == HttpContext.Current.User.Identity.Name).SingleOrDefault();
teamToAdd.Users.Add(currentUser);
var teamAdded = _ctx.Teams.Add(teamToAdd);
Save();
return teamAdded;
I get the following error in the response inner exception:
"Self referencing loop detected with type 'MatchMaker.Data.Team'. Path 'Users[0].Teams'."
There is obviously a circular reference going on but i want a Team to be able to have many Users and a User to be able to have many Teams. Is there any way of getting past this withouth creating DTOs?

Mapping many to many relationship

I am have some trouble getting Entity Framework to handle a many to many relationship in my data schema. Here is my model:
public class User
{
public int UserId { get; set; }
public int Username { get; set; }
public IEnumerable<Customer> Customers { get; set; }
...
}
public class Customer
{
public int CustomerId { get; set; }
...
}
public class CustomerUser
{
public int CustomerUserId { get; set; }
public int CustomerId { get; set; }
public int UserId { get; set; }
public DateTime CreatedTimestamp { get; set; }
...
}
Here is the mapping:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<User>().HasKey(u => u.UserId).ToTable("Users");
modelBuilder.Entity<Customer>().HasKey(c => c.CustomerId).ToTable("Customer");
modelBuilder.Entity<CustomerUsers>().HasKey(cu => cu.CustomerUserId).ToTable("CustomerUsers");
modelBuilder.Entity<CustomerUsers>()
.HasRequired(cu => cu.User)
.WithRequiredDependent()
.Map(m =>
{
m.ToTable("Users");
m.MapKey("CustomerUsers.UserId");
});
}
My database has a Users, Customers, and CustomerUsers table with columns that match the model.
I am trying to execute the following query:
result = (from u in context.Users
join customerUsers in context.CustomerUsers on u.UserId equals customerUsers.User.UserId
join customers in context.Customers on customerUsers.CustomerId equals customers.CustomerId into ps
select new
{
User = u,
Customers = ps
}).ToList().Select(r => { r.User.Customers = r.Customers.ToList(); return r.User; });
When I run the code, I get the following error:
The Column 'CustomerUserId' specified as part of this MSL does not exist in MetadataWorkspace
Can anyone see what is wrong with my approach?
Thanks!
I should note that I am intentionally trying to not include a reference to the CustomerUsers table from either the Customer or User class. The majority of the time, the payload of the CustomerUsers table is not important, only which customers are associated to which users. There are some reporting scenarios where the additional information in the join table is necessary, but since this is not the typical situation, I would like to avoid cluttering up the models by having this additional indirection.
Instead of trying to map this as many to many, map it as two one to many relationships. See the discussion of many to many join tables with payload in Many-to-Many Relationships in this tutorial:
http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/creating-a-more-complex-data-model-for-an-asp-net-mvc-application
For your model you will need probably two one-to-many relationships and the following navigation properties:
public class User
{
public int UserId { get; set; }
public int Username { get; set; }
// ...
public ICollection<CustomerUser> CustomerUsers { get; set; }
}
public class Customer
{
public int CustomerId { get; set; }
//...
public ICollection<CustomerUser> CustomerUsers { get; set; }
}
public class CustomerUser
{
public int CustomerUserId { get; set; }
public int CustomerId { get; set; }
public int UserId { get; set; }
public DateTime CreatedTimestamp { get; set; }
//...
public User User { get; set; }
public Customer Customer { get; set; }
}
And the following mapping:
modelBuilder.Entity<CustomerUser>()
.HasRequired(cu => cu.User)
.WithMany(u => u.CustomerUsers)
.HasForeignKey(cu => cu.UserId);
modelBuilder.Entity<CustomerUser>()
.HasRequired(cu => cu.Customer)
.WithMany(c => c.CustomerUsers)
.HasForeignKey(cu => cu.CustomerId);