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
Related
I'm doing some practice with Entity Framework and I want to create a web-api backend, which is able to manage requests by interacting with a MySql database and by responding with JSON strings in the message body of the replies. I'm quite new to it and I'm trying to learn it solving problem by problem in the project.
An example of the working code at the moment is:
public string getFilmById(int id)
{
return JsonSerializer.Serialize(ctx.Films.ToList().Where(filmToGet => filmToGet.Id == id));
}
Which generates the string:
[{"Id":7,"Title":"Dune","Genre":"Sci-fi","Duration":155,"Direction":[],"Interpretation":[]}]
Now, what I want to do is to include in the string the directors and the actors of the film. I've created all the models of the backend with a database-first approach, by importing and converting MySql tables into classes and by generating the dbcontext class automatically. This implies that I also have the Direction class to link Film and Director, because the relationship is Many to Many (the same is for Interpretation and Actor). Here the code:
public partial class Film
{
public Film()
{
Direction = new HashSet<Direction>();
Interpretation = new HashSet<Interpretation>();
}
public int Id { get; set; }
public string Title { get; set; }
public string Genre { get; set; }
public int? Duration { get; set; }
public virtual ICollection<Direction> Directions { get; set; }
public virtual ICollection<Interpretation> Interpretations { get; set; }
}
public partial class Direction
{
public int Id { get; set; }
public int? IdDirector { get; set; }
public int? IdFilm { get; set; }
public virtual Film IdFilmNavigation { get; set; }
public virtual Director IdDirectorNavigation { get; set; }
}
public partial class Director
{
public Director()
{
Directions = new HashSet<Direction>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public virtual ICollection<Direction> Directions { get; set; }
}
In the end: how can I include Directors and Actors in the Film instance and make them appear in that json string? Technically this is a simple JOIN after all, but I don't really know how to do it using these classes.
Thank you for the help!
Here's the repo with all the code if can help:
https://github.com/marco-savino/film_archive_project.git
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.
Using an example, I have the following two Entities. The OrderEntity contains a collection of OrderLineEntites
public class OrderEntity
{
public string Reference { get; set; }
public string Description { get; set; }
public bool Confirmed { get; set; }
[NotMapped]
public int OrderLineCount { get; set; }
[InverseProperty("Order")]
public virtual ICollection<OrderLineEntity> OrderLineEntity__OrderEntity { get; set; }
}
public class OrderLineEntity
{
public string Name { get; set; }
public string Description { get; set; }
}
Using the following code I can load all the OrderLineEntities for all confirmed orders.
DbSet<OrderEntity> orderEntity.Where(x => x.Confirmed).Include(x => x.OrderLineEntity__OrderEntity)
What I need to do is set the non-mapped OrderLineCount property with the Count of the OrderLine records (to save actually loading them).
So for each loaded Order I have a fully populated Entity including the [NotMapped] property with an empty OrderLine collection.
Advise would be appreciated :)
Thanks
You can do this, but you have to change your approach. You have to manually map the objects yourself:
var query = from a in context.Orders.Where(x => x.Confirmed)
select new OrderEntity
{
Reference = a.Reference,
Description = a.Description,
Confirmed = a.Confirmed,
OrderLineCount = a.OrderLineEntity__OrderEntity.Count
};
return query.ToList();
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.
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