I've an application in Asp.NET Core 3.1 MVC with EF Core and Identity.
I've two tables Calls and AspNetUsers. AspNetUsers has many Calls and one Call has one AspNetUsers.
The Calls table structure is okay, I think. But now I need to get Calls from AspNetUsers.
In CallsController I'm trying: IList<Call> calls = this.User.Calls; but no success.
I tried:
IList<Call> calls = this._context.Calls.Where(x => x.UserId == this._userManager.GetUserId(this.User)).ToList();
I've success. But do it is correct?
So, in application i've identity classes and an ApplicationUser like this:
public class ApplicationUser : IdentityUser
{
public virtual IList<Call> Calls { get; set; }
}
And in Startup class in ConfigureServices method:
services.AddDefaultIdentity<ApplicationUser>(options =>
options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
So, What's the better way to get Calls from AspNetUsers? Thanks!
You can set ApplicationUser like :
public class ApplicationUser : IdentityUser
{
public virtual ICollection<Call> Calls { get; set; }
}
Call.cs:
public class Call
{
public int ID { get; set; }
public string name { get; set; }
// other properties
public string UserID { get; set; }
[ForeignKey("UserID")]
public virtual ApplicationUser ApplicationUser { get; set; }
}
In ApplicationDbContext , add :
public virtual DbSet<Call> Calls { get; set; } //add this line
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
Then you can query the current user's call by :
if (User.Identity.IsAuthenticated)
{
var userID = User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value;
var calls = _applicationDbContext.Users.Include(u => u.Calls).First(u => u.Id == userID).Calls.ToList();
//or
var callsa = _applicationDbContext.Calls.Where(p => p.UserID == userID).ToList();
}
ApplicationUser should be
public class ApplicationUser : IdentityUser
{
public virtual ICollection<Call> Calls { get; set; }
}
Call entity should be
public class Call
{
public int ID { get; set; }
//...
public string ApplicationUserId { get; set; }
[ForeignKey(nameof(ApplicationUserId))]
public virtual ApplicationUser ApplicationUser { get; set; }
}
and, of course, you should override the OnModeCreating method in your DbContext like this
public class ApplicationDbContext: DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options){}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Call>()
.HasOne(x => x.ApplicationUser)
.WithMany(x => x.Calls);
}
//...DbSets..
}
and finally, load all your calls in Calls collection of ApplicationUser
var user = await _context.ApplicationUsers.FindAsync(_userManager.GetUserId(this.User));
await context.Entry(user)
.Collection(x => x.Calls)
.LoadAsync();
Now, you have all your calls loaded in Calls collection of the current user.
Related
I'm using an external library to return data to me, the library has a lot of fields in it and goes quite deep with nested objects.
My class looks something like this;
public class Dto
{
public Dto(Val val)
{
Val = val;
}
[Key]
public int Id { get; set; }
public Val Value{ get; set; }
}
And when trying to save the changes to EF I get the error;
Cannot insert explicit value for identity column in table 'Value' when IDENTITY_INSERT is set to OFF.
When looking through the migrations it appears as if the Primary Key has been set on a few properties within the Value object. I've looked and looked but can't find a way to stop the migration automatically assigning primary keys. I've found stuff such as in the example above using the;
[Key]
attribute and adding bits and pieces into the OnModelCreating override but nothing has came up with a successful result.
Edit to give some more clarity instead of an example.
[DbContext(typeof(SummonerDtoContext))]
[Migration("20180314210242_Migration8")]
partial class Migration8
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.0.2-rtm-10011")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("LccWebAPI.Models.SummonerDto", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<long?>("SummonerId");
b.HasKey("Id");
b.HasIndex("SummonerId");
b.ToTable("Summoners");
});
modelBuilder.Entity("RiotSharp.SummonerEndpoint.Summoner", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd();
b.Property<long>("AccountId");
b.Property<long>("Level");
b.Property<string>("Name");
b.Property<int>("ProfileIconId");
b.Property<int>("Region");
b.Property<DateTime>("RevisionDate");
b.HasKey("Id");
b.ToTable("Summoner");
});
modelBuilder.Entity("LccWebAPI.Models.SummonerDto", b =>
{
b.HasOne("RiotSharp.SummonerEndpoint.Summoner", "Summoner")
.WithMany()
.HasForeignKey("SummonerId");
});
#pragma warning restore 612, 618
}
}
}
and my actual data object I'm trying to store;
public class SummonerDto
{
public SummonerDto(Summoner summoner)
{
Summoner = summoner;
}
public int Id { get; set; }
public Summoner Summoner { get; set; }
}
and my context;
public class SummonerDtoContext : DbContext
{
public SummonerDtoContext(DbContextOptions<SummonerDtoContext> options)
: base(options)
{ }
public DbSet<SummonerDto> Summoners { get; set; }
}
I don't have access to modify the inside of the Summoner object itself to add annotations to ignore them as keys.
And the model structure of the Summoner object which I have no access to amend;
public class Summoner : SummonerBase
{
[JsonProperty("profileIconId")]
public int ProfileIconId { get; set; }
[JsonConverter(typeof(DateTimeConverterFromLong))]
[JsonProperty("revisionDate")]
public DateTime RevisionDate { get; set; }
[JsonProperty("summonerLevel")]
public long Level { get; set; }
}
And the base;
public class SummonerBase
{
public Region Region { get; set; }
[JsonProperty("id")]
public long Id { get; set; }
public long AccountId { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
Edit : RESOLVED
After 3 hours of trying to figure this out I've finally managed to solve it, since I don't have access to annotate the models directly, I'd previously tried accessing the Ids through my SummonerDto model. Instead I accecssed them directly and it's worked.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<SummonerDto>()
.HasKey(c => c.Id);
modelBuilder.Entity<Summoner>().Property(x => x.Id).ValueGeneratedNever();
modelBuilder.Entity<Summoner>().Property(x => x.ProfileIconId).ValueGeneratedNever();
modelBuilder.Entity<SummonerBase>().Property(x => x.Id).ValueGeneratedNever();
base.OnModelCreating(modelBuilder);
}
I am completely new to linq and need help.
These are my poco classes:
public class User {
public User()
{
this.Profiles = new List<Profile>();
}
public Guid ID { get; set; }
public bool IsValid{ get; set; }
public virtual ICollection<Profile> Profiles { get; set; }
}
public class Profile {
public Profile() {
this.Users = new List<User>();
this.Customers = new List<Customer>();
}
public Guid ID { get; set; }
public string Name { get; set; }
public virtual ICollection<User> Users { get; set; }
public virtual ICollection<Customer> Customers { get; set; }
}
public class Customer {
public Customer()
{
this.Profiles = new List<Profile>();
}
public Guid ID { get; set; }
public string Number { get; set; }
public virtual ICollection<Profile> Profiles { get; set; }
}
I would like to search for valid Users with special customers. Special customers would come from another user. So I would send another user as method argument.
Is it even possible with linq or I need stored procedure to solv the problem?
Best regards
You can try this:
public static List<User> FindAllUsersBySameCustomers(User sourceuser)
{
var res = sourceuser.Profiles.SelectMany(p => p.Customers)
.SelectMany(c => c.Profiles)
.SelectMany(p => p.Users)
.Distinct();
return res.ToList();
}
But beware, it will work only if your relations are populated (included) like in my example here.
NOTE
You should not call virtual member inside the constructor. Anwer is here on SO: Virtual member call in a constructor
Try this..
/// <summary>
/// Search for valid Users with special customers.
/// Special customers would come from another user.
/// So I would send another user as method argument.
/// </summary>
/// <returns></returns>
public List<User> FindValidUsersWithSpecialCustomers(List<User> allUsers, User anotherUser)
{
var specialCustomers = anotherUser.Profiles.SelectMany(aProfile => aProfile.Customers);//.Select(cust => cust.Number == "SpecialCustomerNumber" && cust.ID == new Guid("SpecialCustomerGuid"));
Func<IEnumerable<Customer>, IEnumerable<Customer>, Boolean> IsSpecialCustomersPresentInThisCustomersList =
delegate(IEnumerable<Customer> customerList, IEnumerable<Customer> specialCustomersList)
{
if ((from cust in customerList where specialCustomersList.Contains(cust) select cust).Any())
return true;
else
return false;
};
var validUsersWithSpecialCustomers = (from user in allUsers where user.IsValid && IsSpecialCustomersPresentInThisCustomersList(user.Profiles.SelectMany(p => p.Customers), specialCustomers) select user);
return validUsersWithSpecialCustomers.ToList();
}
I'm creating an MVC3 asp.net application using Entity Framework 4 and C#.
I've tried to read up on EF and model binding, lazy loading, etc. But I've hit an obstacle.
I have a User Model. The Store and UserType models can have an ICollection of Users. When I add a User with the Create Action, How do I specify multiple parents?
I think that I only know how to add if there is one parent.
My Models:
public class UserType
{
public virtual int ID { get; set; }
public virtual string UserTypeName { get; set; }
public virtual ICollection<User> Users { get; set; }
}
public class Store
{
public virtual int ID { get; set; }
public virtual string StoreName { get; set; }
public virtual Address StoreAddress { get; set; }
public virtual ICollection<Workroom> Workrooms { get; set;}
public virtual ICollection<User> Users { get; set; }
}
public class User
{
public virtual int ID { get; set; }
public virtual string Username { get; set; }
public virtual string Email { get; set; }
public virtual Store Store { get; set; }
public virtual UserType UserType { get; set; }
}
Here is my db context:
public DbSet<Workroom> Workrooms { get; set; }
public DbSet<Ticket> Tickets { get; set; }
public DbSet<Customer> Customers { get; set; }
public DbSet<Store> Stores { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<UserType> UserTypes { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Store>()
.HasMany(store => store.Workrooms)
.WithRequired(workroom => workroom.Store);
modelBuilder.Entity<Store>()
.HasMany(store => store.Users)
.WithRequired(user => user.Store);
modelBuilder.Entity<UserType>()
.HasMany(usertype => usertype.Users)
.WithRequired(user => user.UserType);
base.OnModelCreating(modelBuilder);
}
Here's my create action:
public ActionResult Create()
{
return View(new User());
}
//
// POST: /Users/Create
[HttpPost]
public ActionResult Create(User newUser)
{
try
{
int storeID = newUser.Store.ID;
var store = _db.Stores.Single(r => r.ID == storeID);
store.Users.Add(newUser);
_db.SaveChanges();
return RedirectToAction("Index");
}
catch (Exception ex)
{
ModelState.AddModelError("", ex.InnerException.Message);
return View();
}
}
Do I just add another "Add" call for UserType? for example:
int userTypeID = newUser.UserType.ID
var usertype = _db.UserTypes.Single(s => s.ID == userTypeID)
How would the Entity Framework know that Users has another Parent??? ...do I care?
My hunch is that I should be doing this a different way, more specific and more accurate.
In this case, you probably want to add the user to the Users table, rather than the Stores. Then you assign the StoreID and UserTypeID to the user before you commit.
It looks like you're already setting the StoreID in your UI, are you doing the same for UserType? If so, then just add the user to the users table and you should be good.
I am developing an asp.net mvc application, which has these enity classes:
public class Person
{
public int PersonID { get; set; }
public string PersonPicAddress { get; set; }
public virtual List<Person_Local> PersonLocal { get; set; }
}
public class Person_Local
{
public int PersonID { get; set; }
public int CultureID { get; set; }
public string PersonName { get; set; }
public string PersonFamily { get; set; }
public string PersonAbout { get; set; }
public virtual Culture Culture { get; set; }
public virtual Person Person { get; set; }
}
public class Culture
{
public int CultureID { get; set; }
[Required()]
public string CultureName { get; set; }
[Required()]
public string CultureDisplay { get; set; }
public virtual List<HomePage> HomePage { get; set; }
public virtual List<Person_Local> PersonLocak { get; set; }
}
I defined an action with [Httppost] attribute, which accepts complex object from a view.
Here is the action :
[HttpPost]
public ActionResult CreatePerson([Bind(Prefix = "Person")]Person obj)
{
AppDbContext da = new AppDbContext();
//Only getting first PersonLocal from list of PersonLocals
obj.PersonLocal[0].Person = obj;
da.Persons.Add(obj);
da.SaveChanges();
return Jsono(...);
}
But when it throws error as below :
Exception:Thrown: "Invalid column name 'Culture_CultureID'." (System.Data.SqlClient.SqlException)
A System.Data.SqlClient.SqlException was thrown: "Invalid column name 'Culture_CultureID'."
And the insert statement :
ADO.NET:Execute Reader "insert [dbo].[Person_Local]([PersonID], [PersonName], [PersonFamily], [PersonAbout], [Culture_CultureID])
values (#0, #1, #2, #3, null)
select [CultureID]
from [dbo].[Person_Local]
where ##ROWCOUNT > 0 and [CultureID] = scope_identity()"
The command text "insert [dbo].[Person_Local]([PersonID], [PersonName], [PersonFamily], [PersonAbout], [Culture_CultureID])
values (#0, #1, #2, #3, null)
select [CultureID]
from [dbo].[Person_Local]
where ##ROWCOUNT > 0 and [CultureID] = scope_identity()" was executed on connection "Data Source=bab-pc;Initial Catalog=MainDB;Integrated Security=True;Application Name=EntityFrameworkMUE", building a SqlDataReader.
Where is the problem?
Edited:
Included EntityConfigurations Code:
public class CultureConfig : EntityTypeConfiguration<Culture>
{
public CultureConfig()
{
HasKey(x => x.CultureID);
Property(x => x.CultureName);
Property(x => x.CultureDisplay);
ToTable("Culture");
}
}
public class PersonConfig : EntityTypeConfiguration<Person>
{
public PersonConfig()
{
HasKey(x => x.PersonID);
Property(x=>x.PersonPicAddress);
ToTable("Person");
}
}
public class Person_LocalConfig : EntityTypeConfiguration<Person_Local>
{
public Person_LocalConfig()
{
HasKey(x => x.PersonID);
HasKey(x => x.CultureID);
Property(x=>x.PersonName);
Property(x => x.PersonFamily);
Property(x => x.PersonAbout);
ToTable("Person_Local");
}
}
Try to remove fields CultureID and PersonID from Person_Local class. Because you already has field Person and Culture
It looks like your schema is out of sync with your model. Make sure you understand EF Code first schema update features, which are described in this blog. If you need more sophisticated schema migration, there are some other approaches in answers to this question.
I've a layer name MVCTemplate.Common, having two folders Entities and Mappings. In Entities User.cs and Role.cs is as under respectively:
using System;
using System.Collections.Generic;
namespace MVCTemplate.Common.Entities
{
public class User
{
public virtual Guid UserID { get; set; }
public virtual string UserName { get; set; }
public virtual string Password { get; set; }
public virtual string FullName { get; set; }
public virtual string Email { get; set; }
public virtual TimeSpan LastLogin { get; set; }
public virtual bool IsActive { get; set; }
public virtual DateTime CreationDate { get; set; }
public virtual IList<Role> UserInRoles { get; set; }
public User()
{
UserInRoles = new List<Role>();
}
}
}
using System.Collections.Generic;
namespace MVCTemplate.Common.Entities
{
public class Role
{
public virtual int? RoleID { get; set; }
public virtual string RoleName { get; set; }
public virtual bool IsActive { get; set; }
public virtual string Description { get; set; }
public virtual IList<User> Users { get; set; }
//public virtual IList<RolePermission> RolePermission { get; set; }
public Role()
{
Users = new List<User>();
}
public virtual void AddUsers(User _user)
{
_user.UserInRoles.Add(this);
Users.Add(_user);
}
}
}
Now, In Mappings folder their mappings files is as under:
using FluentNHibernate.Mapping;
using MVCTemplate.Common.Entities;
namespace MVCTemplate.Common.Mappings
{
public class RoleMap : ClassMap<Role>
{
public RoleMap()
{
Table("tblRoles");
Id(role => role.RoleID).GeneratedBy.Identity();
Map(role => role.RoleName).Not.Nullable();
Map(role => role.IsActive).Not.Nullable();
Map(role => role.Description).Not.Nullable();
HasManyToMany(role => role.Users).Cascade.All().Table("tblUserInRoles");
//HasMany(role => role.User);
//HasMany(role => role.RolePermission);
}
}
}
using FluentNHibernate.Mapping;
using MVCTemplate.Common.Entities;
namespace MVCTemplate.Common.Mappings
{
public class UserMap : ClassMap<User>
{
public UserMap()
{
Table("tblUsers");
Id(user => user.UserID).GeneratedBy.Guid();
Map(user => user.UserName).Not.Nullable();
Map(user => user.Password).Not.Nullable();
Map(user => user.FullName).Not.Nullable();
Map(user => user.Email).Not.Nullable();
//Map(user => user.LastLogin).Nullable();
Map(user => user.IsActive).Not.Nullable();
Map(user => user.CreationDate).Not.Nullable();
HasManyToMany(user => user.UserInRoles).Cascade.All().Table("tblUserInRoles");
//HasMany(user => user.UserInRoles);
}
}
}
Now, from controller, I got specific user object in user object and now want to delete it, the simple code is as under:
using System;
using System.Collections.Generic;
using System.Web.Mvc;
using MVCTemplate.BussinessLayer.Facade;
using MVCTemplate.Common.Entities;
namespace MVCTemplate.Web.Controllers
{
public class HomeController : Controller
{
private UserManagement _userManagement;
public ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
_userManagement = new UserManagement();
var oUser = _userManagement.GetUserBy(new Guid("4fb5856a-58d9-4b78-8d08-bce645bc93c7"));
oUser.UserInRoles = new List<Role>();
_userManagement.Delete(oUser);
return View();
}
public ActionResult About()
{
return View();
}
}
}
Now, I just want to delete that user as this user is not exist in any role and there is no entry of it in its junction table(UserInRole). I initialize its Role collection to empty for Count=0, but after calling deleting method it throw an error with sqlQuery which is as under:
could not delete collection: [MVCTemplate.Common.Entities.User.UserInRoles#4fb5856a-58d9-4b78-8d08-bce645bc93c7][SQL: DELETE FROM tblUserInRoles WHERE User_id = #p0]
Note that in Junction table tblUserInRole there no field of that name User_id as mentioned in error, due to which in the inner exception it is telling that column name User_id not exist. But in junction table I have only two field 1) UserID and 2) RoleID.
Any suggestion how to resolve it?
looks like a mapping error to me. Change:
HasManyToMany(user => user.UserInRoles).Cascade.All().Table("tblUserInRoles");
To
HasManyToMany(user => user.UserInRoles)
.Cascade.All()
.Table("tblUserInRoles")
.ParentKeyColumn("UserID")
.ChildKeyColumn("RoleID");