Selecting data from two tables using composite keys - c#

I'm trying to select the users with their modules using the composite key. I can select on MySQL with SQL query but I'm new to entity framework and I'm having troubles figuring out. I appreciate any help that I can get.
public class module
{
public int moduleid { get; set; }
public string modulename { get; set; }
[ForeignKey("module_moduleid")]
public ICollection<session> sessions { get; set; }
public ICollection<user_has_module> usermodule { get; set; }
}
public class user_has_module
{
public String userid { get; set; }
public int moduleid { get; set; }
public user user { get; set; }
public module module { get; set; }
}
public class user
{
[Key]
public string userid { get; set; }
public string userpw { get; set; }
public string fullname { get; set; }
public ICollection<user_has_module> usermodule { get; set; }
}
This is my database context class.
public class DatabaseContext : DbContext
{
public DatabaseContext(DbContextOptions<DatabaseContext> options) : base(options)
{
}
public DbSet<user> user { get; set; }
public DbSet<module> module { get; set; }
public DbSet<user_has_module> user_has_module { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<user_has_module>()
.HasKey(x => new { x.userid, x.moduleid });
modelBuilder.Entity<user_has_module>()
.HasOne(x => x.user)
.WithMany(y => y.usermodule)
.HasForeignKey(y => y.userid);
modelBuilder.Entity<user_has_module>()
.HasOne(x => x.module)
.WithMany(y => y.usermodule)
.HasForeignKey(y => y.moduleid);
}
}
This is the query I'm trying to do in entity framework core.
From user
INNER JOIN user_has_module
ON user.userid = user_has_module.user_userid
INNER JOIN module
ON user_has_module.module_moduleid = module.moduleid;

To retrieve data from three tables using a composite key, you can be inspired by the following example :
var query = from o in db.Orders
from p in db.Products
join d in db.OrderDetails
on new {o.OrderID, p.ProductID} equals new {d.OrderID, d.ProductID} into details
from d in details
select new {o.OrderID, p.ProductID, d.UnitPrice};
Hope it helps !

Related

How to return objects from many to many relation Db - entityframework

Im trying to return a List of products of a specific user by user Id, but that seems to not work
My Product class
public class Product
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public int Quantity { get; set; }
public List<User>? Users { get; set; }
}
My user class
public class User
{
[Key]
public Guid Id { get; set; }
[Required] [MaxLength(15)]
public string Username { get; set; }
[Required]
public string Name { get; set; }
public string Surname { get; set; }
public string PasswordHash { get; set; }
public string Salt { get; set; }
public List<Product>? Products { get; set; }
}
So im adding and Product to Db, this is working
And then im adding the product to Order by this method
Guid id is a user's id
public void AddProduct(Product product, Guid id)
{
var user = _context.Users.First(u => u.Id == id);
var p = _context.Products.First(p => p.Id == product.Id);
if (user.Products == null || p.Users == null)
{
user.Products = new List<Product>();
p.Users = new List<User>();
}
user.Products.Add(p);
p.Users.Add(user);
_context.SaveChanges();
}
And this also seems to work:
image of ProductUser table from db
So how can I return a List of Products which specific user have?
I've tried this:
private Order BuildOrder(Guid id)
{
var user = _context.Users.First(u => u.Id == id);
/*if (user.Products is null)
{
user.Products = new List<Product>();
}*/
var x = _context.Products.Where(p => p.Id == 1);
/*
var products = user.Products.ToList();*/
var order = new Order
{
Products = x.ToList()
};
return order;
But this is returning me null, like Adding Products is not working
Result of this method
Order class:
public class Order
{
public List<Product> Products { get; set; }
}
DbContext:
using Application.Api.Models;
using Microsoft.EntityFrameworkCore;
namespace Application.Api.Data;
public class ApplicationContext : DbContext
{
public ApplicationContext(DbContextOptions<ApplicationContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.UseSerialColumns();
modelBuilder.Entity<User>(eb =>
{
eb.HasMany(u => u.Products).WithMany(p => p.Users);
});
}
public DbSet<User> Users { get; set; }
public DbSet<Product> Products { get; set; }
}
If that's not enough informations comment what I need to add
you need to explicitly include the Products for the user
var speceficUserWithProducts = context.Users.Include(u => u.Products).FirstOrDefault(u => u.Id == id);

AutoMapper with different children

I have an entity as Plan with multiple sub-plans (children), each of which could be null.
For the PlanDto, I am trying to load up a list of all children rather than having a separate property for each child like the entity.
I have already achieved it manually through a foreach loop but now I am trying to do it via AutoMapper, which is failing for some reason.
Entities:
public class Plan
{
public virtual int Id { get; set; }
public DateTime Date { get; set; }
public virtual PlanDetail PlanChild1 { get; set; }
public virtual ObservationCare PlanChild2 { get; set; }
}
public class PlanDetail
{
public virtual int Id { get; set; }
public virtual Plan Plan { get; set; }
public virtual string Description { get; set; }
}
public class ObservationCare
{
public virtual int Id { get; set; }
public virtual Plan Plan { get; set; }
public virtual string Description { get; set; }
}
DTOs:
public class PlanDto: EntityDto
{
public DateTime Date { get; set; }
public IEnumerable<ChildPlan> ChildPlan { get; set; }
}
public class ChildPlan : EntityDto
{
public ChildPlanType Type { get; set; }
}
public enum ChildPlanType
{
PlanDetail,
ObservationCare
}
AutoMapper config:
configuration.CreateMap<Plan, PlanDto>();
configuration.CreateMap<PlanDetail, ChildPlan>()
.ForMember(dto => dto.Type, options => options.MapFrom(p => ChildPlanType.PlanDetail));
configuration.CreateMap<ObservationCare, ChildPlan>()
.ForMember(dto => dto.Type, options => options.MapFrom(p => ChildPlanType.ObservationCare));
Mapping attempt:
var output = new List<PlanDto>();
var plans = await _planRepository.GetAll().ToList();
foreach (var plan in plans)
{
output.Add(ObjectMapper.Map<PlanDto>(plan));
}
I do not know why ChildPlan DTOs in the output list are always null!
You have to specify the mapping for PlanDto.ChildPlan:
configuration.CreateMap<Plan, PlanDto>()
.ForMember(dto => dto.ChildPlan,
options => options.MapFrom(
p => new object[] { p.PlanChild1, p.PlanChild2 }.Where(c => c != null)));
If you are using Entity Framework Core, you have to use eager-loading:
var plans = await _planRepository.GetAll()
.Include(p => p.PlanChild1)
.Include(p => p.PlanChild2)
.ToList();
There's also a simpler and more efficient way to map a list:
var output = ObjectMapper.Map<List<PlanDto>>(plans);

IQueryable Not Returning Associated Data

I am using EF6, I have a 1:N relationship between Owners and Widgets. I can't seem to get the associated Owner information.
public partial class Owners
{
public Owners()
{
Widgets = new HashSet<Widgets>();
}
public int Id { get; set; }
public string OwnerName { get; set; }
public virtual ICollection<Widgets> Widgets { get; set; }
}
public partial class Widgets
{
public int id { get; set; }
public int OwnerId { get; set; }
public string WidgetName { get; set; }
public string WidgetType { get; set; }
public virtual Owners Owners { get; set; }
}
public partial class Model1 : DbContext
{
public Model1(): base("name=Model1"){}
public virtual DbSet<Owners> Owners { get; set; }
public virtual DbSet<Widgets> Widgets { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Owners>()
.HasMany(e => e.Widgets)
.WithRequired(e => e.Owners)
.HasForeignKey(e => e.OwnerId)
.WillCascadeOnDelete(false);
}
}
The problem is when I run following query I only get information for Widgets
and nothing for Owners. If I pull the generated SQL out and run it in the database I get all the Information and Associated Entity Information?
I believe I'm overlooking something simple here.
using (var db = new Model1())
{
var rslt = db.Widgets.Include(y => y.Owners);
var rslt2 = await rslt.Where(s => s.WidgetType == "Garthug").ToListAsync();
return rslt2;
}
This is the EF generated SQL statement that gets created and shows all the correct information that I'm looking for when I run in the Database. (I hand typed it but it should be correct)
SELECT
Widgets.id AS id,
Widgets.OwnerId AS OwnerId,
Widgets.WidgetName AS WidgetName,
Widgets.WidgetsType AS WidgetType,
Owners.Id AS Id1,
Owners.OwnerName AS OwnerName
FROM [dbo].Widgets AS Widgets
INNER JOIN [dbo].Owners AS Owner ON Widgets.OwnerId = Owners.Id
WHERE Widgets.WidgetType = 'Garthug'
It Appears that my setup is Correct for EVERY table except Asp Identity Tables... Does anyone know why?
Widgets.OwnerId is associated with Owner.Id so the types are same
But the sort order and equality aren't necessarily the same between .NET and the database. So you could have a collation conflict between the database and EF, where the Widget.OwnerId's match Owner.Id's in the collation of the database, but not in .NET's string comparison rules.
EG
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ef62test
{
class Program
{
public partial class Owner
{
public string Id { get; set; }
public string OwnerName { get; set; }
public virtual ICollection<Widget> Widgets { get; } = new HashSet<Widget>();
}
public partial class Widget
{
public int id { get; set; }
public string OwnerId { get; set; }
public string WidgetName { get; set; }
public string WidgetType { get; set; }
public virtual Owner Owners { get; set; }
}
public partial class Model1 : DbContext
{
public virtual DbSet<Owner> Owners { get; set; }
public virtual DbSet<Widget> Widgets { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Owner>()
.HasMany(e => e.Widgets)
.WithRequired(e => e.Owners)
.HasForeignKey(e => e.OwnerId)
.WillCascadeOnDelete(false);
}
}
static void Main(string[] args)
{
Database.SetInitializer(new DropCreateDatabaseAlways<Model1>());
string ownerId = "owner1";
using (var db = new Model1())
{
db.Database.Log = s => Console.WriteLine(s);
var o = new Owner() { Id = ownerId };
db.Owners.Add(o);
for (int i = 0; i < 10; i++)
{
o.Widgets.Add(new Widget());
}
db.SaveChanges();
ownerId = o.Id;
db.Database.ExecuteSqlCommand("update widgets set ownerId = UPPER(ownerId);");
}
using (var db = new Model1())
{
db.Database.Log = s => Console.WriteLine(s);
db.Configuration.LazyLoadingEnabled = false;
var owner = db.Owners.Include(o => o.Widgets).Where(o => o.Id == ownerId).First();
Console.WriteLine(owner.Widgets.Count());
}
Console.WriteLine("Hit any key to exit.");
Console.ReadKey();
}
}
}
If it is the aspnetusers table, does it exist in the same context as your other table? That would explain why EF was struggling even if the database is not?

How to write below mysql query using Entity Framework with Lambda expression?

SELECT
`Distinct1`.`UserId`,
`Distinct1`.`FirstName`,
`Distinct1`.`LastName`,
`Distinct1`.`EmailAddress`,
FROM ( SELECT DISTINCT
`Extent2`.`UserId`,
`Extent2`.`FirstName`,
`Extent2`.`LastName`,
`Extent2`.`EmailAddress`,
FROM `AssistantTo` AS `Extent1`
INNER JOIN `User` AS `Extent2` ON `Extent1`.`AssistantId` = `Extent2`.`UserId`
INNER JOIN `CustomTagUser` as `Extent3` ON `Extent3`.`UserId` = `Extent2`.`UserId`
WHERE `Extent1`.`OwnerId` = 274 AND `Extent3`.`CustomTagId` = 114
) AS `Distinct1`
This is my Table structure :
I tried using following query but it is giving me error.
var assistants =
dbContext.AssistantsTo
.Include(x => x.Assistant)
.Include(x => x.Assistant.CustomTagUser)
.Where(at =>
at.OwnerId == currentUser.UserId
&& (at.Assistant.CustomTagUser.Count(y => y.CustomTagId == filter) > 0)
)
.Select(at => at.Assistant)
.Distinct()
.ToList();
Error : {"Unknown column 'Extent1.AssistantId' in 'where clause'"}
Basically I have issue with giving filter for
`Extent3`.`CustomTagId` = 114
I think we can use any() but I have bad experience using any() with large data & mysql.
Model classes
public class AssistantTo
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int AssistantToId { get; set; }
public int AssistantId { get; set; }
[ForeignKey("AssistantId")]
public virtual User Assistant { get; set; }
public int OwnerId { get; set; }
[ForeignKey("OwnerId")]
public virtual User Owner { get; set; }
}
public class CustomTagUser
{
[Key]
public int CustomTagUserId { get; set; }
public int CustomTagId { get; set; }
public int UserId { get; set; }
public DateTime CreatedOn { get; set; }
[ForeignKey("CustomTagId")]
public virtual CustomTags CustomTags { get; set; }
[ForeignKey("UserId")]
public virtual User User { get; set; }
}
[Table("User")]
public class User
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmailAddress { get; set; }
public string Password { get; set; }
.....
public ICollection<CustomTagUser> CustomTagUser { get; set; }
}
}
Basically I have main problem with applying this part in EF
AND Extent3.CustomTagId = 114
var assistants =
dbContext.AssistantsTo
.Include(x => x.Assistant)
.Include(x => x.Assistant.CustomTagUser)
.Where(at =>
at.OwnerId == currentUser.UserId &&
(
at.Assistant.CustomTagUser.Select(x => x.CustomTagId).Contains(filter)
)
.Select(at => at.Assistant)
.Distinct()
.ToList();
try this one...

Entity Framework Exception at run time: Entities in participate in the relationship?

While using code first approach when I run my project. During new user registration, the entity framework is throwing this exception:
Additional information: Entities in 'ApplicationDbContext.IdentityUsers' participate in the 'ApplicationUser_UserDetails' relationship. 0 related 'ApplicationUser_UserDetails_Target' were found. 1 'ApplicationUser_UserDetails_Target' is expected.
The exception was thrown:
var manager = new UserManager();
var user = new ApplicationUser() { UserName = UserName.Text };
//This line At the time of creating user
IdentityResult result = manager.Create(user, Password.Text);
I created the schema code:
public class ApplicationUser : IdentityUser
{
public Nullable<DateTime> DateOfCreation { get; set; }
public Nullable<bool> IsActive { get; set; }
public Nullable<DateTime> LastLogin { get; set; }
public UserDetails UserDetails { get; set; }
public virtual ICollection<TaskSheetManagement> TaskSheet { get; set; }
public virtual ICollection<Projects> Projects { get; set; }
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
{
modelBuilder.Entity<IdentityUser>().HasKey(pk => pk.Id).ToTable("Users");
modelBuilder.Entity<ApplicationUser>().HasKey(pk=>pk.Id).ToTable("Users");
modelBuilder.Entity<UserDetails>().HasKey(pk => pk.UserDetailId).ToTable("UserDetails");
modelBuilder.Entity<ApplicationUser>().HasRequired(p => p.UserDetails).WithRequiredPrincipal(c => c.ApplicationUser);
modelBuilder.Entity<ApplicationUser>()
.Property(t => t.UserName).IsRequired()
.HasMaxLength(14)
.HasColumnAnnotation("Index",
new IndexAnnotation(new IndexAttribute("U_Username", 1) { IsUnique = true }));
modelBuilder.Entity<UserDetails>()
.Property(t => t.Email).IsRequired()
.HasMaxLength(25)
.HasColumnAnnotation("Index",
new IndexAnnotation(new IndexAttribute("U_Email", 2) { IsUnique = true }));
base.OnModelCreating(modelBuilder);
}
}
And UserDetails is:
public class UserDetails
{
public int UserDetailId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string CountryName { get; set; }
public string Gender { get; set; }
public string Nic { get; set; }
public string ResidentAddress { get; set; }
public string CellNO { get; set; }
public string PhoneNo { get; set; }
public string Religion { get; set; }
public ApplicationUser ApplicationUser { get; set; }
}
I couldn't find out what this exception is related to. I searched google and implemeted other solutions but couldn't resolve. Help please.
You've created a 1:1 association, but 1:1 associations do not work this way in Entity Framework.
1:1 Associations must share the same primary key. The way you've defined this is two 1:M associations, and they conflict with each other.
If you want a 1:1, then you have to change your Primary Key for UserDetails to be Id, and then you have to map them together with something like:
modelBuilder.Entity<UserDetails>().HasRequired(x => x.ApplicationUser)
.WithRequiredDependent(x => x.UserDetails);

Categories

Resources