I'm having the strangest problem and I know it's because I'm missing something obvious because this set up works fine when I save data and even pull it down.
My app is set up like so ....
WebUI depends on Business Layer .. Business Layer depends on Data Layer (which is where I'm actually pulling the data). The Business Layer does all the "work".
This is where everything dies (Null Exception, Object Reference not set) as soon as I assign something to userInfo.userData.avatarFilepath (which is not null).
namespace pgl.businesslayer
{
public class userCtx
{
private pgl.datalayer.Concrete.EFDbContext context = new pgl.datalayer.Concrete.EFDbContext();
private pgl.datalayer.Concrete.EFUserContext userContext = new pgl.datalayer.Concrete.EFUserContext();
private pgl.datalayer.Concrete.EFDbCompany companyContext = new pgl.datalayer.Concrete.EFDbCompany();
public ViewModels.UserInfo getUserById(int userId)
{
ViewModels.UserInfo userInfo = new ViewModels.UserInfo();
pgl.datalayer.Dtos.pglUserDTO userDL = userContext.getUserByUserId(userId);
userInfo.userData.avatarFilepath = userDL.avatarFilepath;
userInfo.userData.createdBy = userDL.createdBy;
userInfo.userData.createdDate = userDL.createdDate;
userInfo.userData.email = userDL.email;
userInfo.userData.firstName = userDL.firstName;
userInfo.userData.lastName = userDL.lastName;
etc...
}
ViewModels.UserInfo looks like this...
namespace pgl.businesslayer.ViewModels
{
public class UserInfo
{
// user info
public pgl.businesslayer.Dto.pglUser userData { get; set; }
// salon info
public List<pglSalon> salonsData { get; set; }
// company info
public pglCompany companyData { get; set; }
}
pglUser in the business layer looks like this and is just a POCO
namespace pgl.businesslayer.Dto
{
public class pglUser
{
public int userId { get; set; }
public int companyId { get; set; }
public string firstName { get; set; }
public string lastName { get; set; }
public string email { get; set; }
public string username { get; set; }
public byte[] passwordSalt { get; set; }
public byte[] passwordKey { get; set; }
public DateTime createdDate { get; set; }
public int createdBy { get; set; }
public bool passwordResetRequired { get; set; }
public string passwordHash { get; set; }
public string tempPassword { get; set; }
public string userType { get; set; }
public string avatarFilepath { get; set; }
public string timeZone { get; set; }
}
}
And in userContext this is how I am pulling the user data...
public pgl.datalayer.Dtos.pglUserDTO getUserByUserId(int userId)
{
var getUser = (from u in context.pglUser
select new pgl.datalayer.Dtos.pglUserDTO
{
username = u.username,
companyId = u.companyId,
userId = u.userId,
userType = u.userType,
firstName = u.firstName,
lastName = u.lastName,
email = u.email,
createdDate = u.createdDate,
createdBy = u.createdBy,
passwordResetRequired = u.passwordResetRequired,
tempPassword = u.tempPassword,
avatarFilepath = u.avatarFilepath,
timeZone = u.timeZone
}).Where(u => u.userId == userId).FirstOrDefault();
return getUser;
}
pgl.datalayer.Dtos.pglUserDTO looks like this...
namespace pgl.datalayer.Dtos
{
public class pglUserDTO
{
public int userId { get; set; }
public int companyId { get; set; }
public string firstName { get; set; }
public string lastName { get; set; }
public string email { get; set; }
public string username { get; set; }
public byte[] passwordSalt { get; set; }
public byte[] passwordKey { get; set; }
public DateTime createdDate { get; set; }
public int createdBy { get; set; }
public bool passwordResetRequired { get; set; }
public string passwordHash { get; set; }
public string tempPassword { get; set; }
public string userType { get; set; }
public string avatarFilepath { get; set; }
public string timeZone { get; set; }
}
}
Even if I assign userInfo.userData.avatarFilepath = "WHATUP!!!" it throws the same error. This has got to be something stupid and simple. I can save data with no problem and when I debug I can see that it is actually pulling the correct user ID and it's associated data. It's just that pgl.businesslayer.ViewModels.UserInfo seems to be un-instantiated. I'm at a loss. I can provide more info... and keep in mind I'm kind of at my wits end so I tried doing weird things like adding (probably) unnecessary DTOs. Any ideas?
You don't appear to be creating the userData object anywhere. When you create a new instance of UserInfo, or in its constructor, try adding:
userData = new pgl.businesslayer.Dto.pglUser();
Or alternatively:
ViewModels.UserInfo userInfo = new ViewModels.UserInfo();
pgl.datalayer.Dtos.pglUserDTO userDL = userContext.getUserByUserId(userId);
userInfo.userData = new pgl.businesslayer.Dto.pglUser {
avatarFilepath = userDL.avatarFilepath,
createdBy = userDL.createdBy,
createdDate = userDL.createdDate,
email = userDL.email,
firstName = userDL.firstName,
lastName = userDL.lastName
};
If you always want to initialise UserInfo with an empty userData member, you could include the creation within the constructor:
namespace pgl.businesslayer.ViewModels
{
public class UserInfo
{
// Default constructor
public UserInfo()
{
userData = new pgl.businesslayer.Dto.pglUser();
}
// user info
public pgl.businesslayer.Dto.pglUser userData { get; set; }
// salon info
public List<pglSalon> salonsData { get; set; }
// company info
public pglCompany companyData { get; set; }
}
}
Related
I have two table like this -
public class Job
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime AddedTime { get; set; } = DateTime.Now;
public DateTime LastEdit { get; set; } = DateTime.Now;
public string Explanation { get; set; }
public string PhotoString { get; set; }
public bool isActive { get; set; } = true;
public int CompanyId { get; set; }
public Company Company { get; set; }
}
and company -
public class Company
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string Explanation { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public string PhotoString { get; set; }
public bool isActive { get; set; } = true;
public int AppUserId { get; set; }
public AppUser AppUser { get; set; }
public List<Job> Jobs { get; set; }
}
I only want to get AppUserId from Company and all Jobs from every Company. I tried this and it gave me error.
using var context = new SocialWorldDbContext();
return await context.Jobs.Where(I => I.isActive == true && I.Company.isActive).Include(I=>I.Company.AppUserId).ToListAsync();
So my question is there any way I can get this data from parent?
Include adds whole entities to the output. To add just one property use Select, something like
context.Jobs
.Where(I => I.isActive == true && I.Company.isActive)
.Select(e => new {Job=e, CompanyAppUserId = e.Company.AppUserId})
.ToListAsync();
I wanted to use a repository option that first retrieves all records but also the includes as well and then select one client based on a given Id using a where clause. I also wanted to include all the notes for this entity.. Client.. as well as its address and Jobs via the includes however if I do try and project the Address to an AddressDto and a collection of ClientNotes to a list of ClientNotesDto it errors with
"Data is Null. This method or property cannot be called on Null
values."
OK so here is the client entity where the clients are loaded from...
using JobsLedger.INTERFACES;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace JobsLedger.DATA.ENTITIES
{
#nullable enable
public class Client : IEntityBase, IAuditedEntityBase
{
public Client()
{
ClientNotes = new List<Note>();
Jobs = new List<Job>();
}
[Key]
public int Id { get; set; }
public string ClientNo { get; set; } = default!;
public bool Company { get; set; }
public string CompanyName { get; set; } = null!;
public string Abn { get; set; } = null!;
public bool IsWarrantyCompany { set; get; }
public bool RequiresPartsPayment { set; get; }
public string ClientFirstName { get; set; } = null!;
public string ClientLastName { get; set; } = null!;
public string Email { get; set; } = null!;
public string MobilePhone { get; set; } = null!;
public string Phone { get; set; } = null!;
public string Address1 { get; set; } = null!;
public string Address2 { get; set; } = null!;
public string BankName { get; set; } = null!;
public string BankBSB { get; set; } = null!;
public string BankAccount { get; set; } = null!;
public bool Active { get; set; }
public DateTime? DateDeActivated { get; set; }
public bool Activity { get; set; }
// One warranty company client to a job.
public int? WarrantyCompanyId { get; set; }
public virtual Job WarrantyCompany { get; set; } = null!;
// One suburb to a client.
public int? SuburbId { get; set; }
public virtual Suburb Suburb { get; set; } = null!;
// If its a warranty company then we simply link it one to one to the brand id.
public virtual Brand Brand { get; set; } = null!;
// Multiple notes for each client.
public virtual ICollection<Note> ClientNotes { get; }
// Multiple jobs for each client.
public virtual ICollection<Job> Jobs { get; set; }
public virtual ICollection<Job> WarrantyCompanyJobs { get; } = default!;
}
#nullable disable
}
Here is the clientDto..
using System.Collections.Generic;
using JobsLedger.MODELS.API.App.Job;
using JobsLedger.MODELS.Common.Address;
using JobsLedger.MODELS.Common.Notes;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using Newtonsoft.Json;
namespace JobsLedger.MODELS.API.App.Client
{
public class ClientDetailsDto
{
public ClientDetailsDto()
{
Address = new AddressDto();
//ClientNotes = new List<ClientNoteDto>();
//ClientJobs = new List<ClientJobDto>();
}
[Key]
public int Id { get; set; }
public string ClientNo { get; set; }
public bool Company { get; set; }
public bool IsWarrantyCompany { set; get; }
public string CompanyName { get; set; }
public string ClientFirstName { get; set; }
public string ClientLastName { get; set; }
public string MobilePhone { get; set; }
public string DeActivated { get; set; }
public string CreatedOn { get; set; }
public string CreatedBy { get; set; }
public string ModifiedOn { get; set; }
public string ModifiedBy { get; set; }
public int SuburbId { get; set; }
public AddressDto Address { get; set; }
public ICollection<ClientJobDto> ClientJobs { get; set; }
public IQueryable<ClientNoteDto> ClientNotes { get; set; }
}
}
Yes there are a few properties but its fairly simple.
The repository is using this method to obtain all clients before doing the "Where" clause to get a single client..
public virtual IQueryable<T> AllIncluding(params Expression<Func<T, object>>[] includeProperties)
{
IQueryable<T> query = _context.Set<T>();
foreach (var includeProperty in includeProperties)
{
query = query.Include(includeProperty);
}
return query;
}
Now bear in mind I get the actual client and its actually projected to the DTO. However If I set project just to the ClientDto it works.. I get data back for a single client.
If uncomment the Address and ClientNotes projections it fails with an the above error.
I was under the impression that with includes I should actually get the associated or related entities and I am not. Is it because of lazy loaded etc..
Here is the statement:
var result = ClientDATARepository?.AllIncluding(c => c.Jobs, c => c.ClientNotes, c => c.Suburb).Where(x => x.Id == id).Select(fetchedClient =>
new ClientDetailsDto {
Id = fetchedClient.Id,
ClientNo = fetchedClient.ClientNo,
Company = fetchedClient.Company,
IsWarrantyCompany = fetchedClient.IsWarrantyCompany,
CompanyName = fetchedClient.CompanyName,
ClientFirstName = fetchedClient.ClientFirstName,
ClientLastName = fetchedClient.ClientLastName,
MobilePhone = fetchedClient.MobilePhone,
DeActivated = fetchedClient.DateDeActivated.HasValue ? "true" : "false",
CreatedOn = EF.Property<DateTime>(fetchedClient, "CreatedOn").ToString("dd/MM/yyyy", CultureInfo.CurrentCulture),
ModifiedOn = EF.Property<DateTime>(fetchedClient, "ModifiedOn").ToString("dd/MM/yyyy", CultureInfo.CurrentCulture),
Address = // ..I believe it fails here.
new AddressDto {
Address1 = fetchedClient.Address1,
Address2 = fetchedClient.Address2,
SuburbId = fetchedClient.Suburb.Id,
SuburbName = fetchedClient.Suburb.SuburbName,
StateShortName = fetchedClient.Suburb.State.StateShortName,
Postcode = fetchedClient.Suburb.PostCode,
},
ClientNotes = fetchedClient.ClientNotes.Select(fetchedClientNote => // ..and here..
new ClientNoteDto {
id = fetchedClientNote.Id,
Details = fetchedClientNote.Details,
NoteType = NoteTypeDATARepository.GetAll().FirstOrDefault(x => x.Id == fetchedClientNote.NoteTypeId).Name,
CreatedOnDate = EF.Property<DateTime>(fetchedClientNote, "CreatedOn").ToString("dd/MM/yyyy", CultureInfo.CurrentCulture),
CreatedOnTime = EF.Property<DateTime>(fetchedClientNote, "CreatedOn").ToString("h:mm tt", CultureInfo.CurrentCulture),
ModifiedOnDate = EF.Property<DateTime>(fetchedClientNote, "ModifiedOn").ToString("dd/MM/yyyy", CultureInfo.CurrentCulture),
ModifiedOnTime = EF.Property<DateTime>(fetchedClientNote, "ModifiedOn").ToString("h:mm tt", CultureInfo.CurrentCulture),
});
As I mentioned when I try and load Address and ClientNotes its throwing the above error saying data cannot be null..
I'd like to know why I cant load Address and ClientNotes and more importantly how to make it so I do load these.. Further.. why cant I do this and still have it as an IQueryable?
I using Realm database at my Xamarin project
I have realm object with this model
public class UserModel: RealmObject
{
public string Id { get; set;}
public string Email { get; set; }
public string Password { get; set; }
public byte[] UserAvatar { get; set; }
public string ApiKey { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string Birthday { get; set; }
public int Country_id { get; set; }
public bool IsAuthorized { get; set; }
public string Base64Avatar { get; set; }
public string Telephone { get; set; }
}
I need to update Name property.
How I try to do this
var realm = Realm.GetInstance();
var user_check = realm.All<UserModel>().First();
user_check.Name = "Test"
and get this error
How I can fix this?
Adding/Updating/Deleting to Realm object must be done inside a transaction, easiest way is to wrap it in Write method.
realm.Write(() =>
{
user_check.Name = "Test";
});
For more info, check the Rleam Write docs
Sql Tables Here
public partial class Users
{
public Users()
{
UsersRelationFollower = new HashSet<UsersRelation>();
UsersRelationFollowing = new HashSet<UsersRelation>();
Vote = new HashSet<Vote>();
VoteRating = new HashSet<VoteRating>();
}
public string Id { get; set; }
public string UserType { get; set; }
public string UserName { get; set; }
public string Mail { get; set; }
public string ImageUrl { get; set; }
public DateTime CreationDate { get; set; }
public DateTime? ModifyDate { get; set; }
public bool State { get; set; }
public virtual UserPasswords UserPasswords { get; set; }
public virtual CorporateProperty CorporateProperty { get; set; }
public virtual UserProperty UserProperty { get; set; }
public virtual ICollection<UsersRelation> UsersRelationFollower { get; set; }
public virtual ICollection<UsersRelation> UsersRelationFollowing { get; set; }
public virtual ICollection<Vote> Vote { get; set; }
public virtual ICollection<VoteRating> VoteRating { get; set; }
}
public partial class UserProperty
{
public string Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public DateTime BirthDay { get; set; }
public string Gender { get; set; }
public string Locale { get; set; }
public string PhoneNumber { get; set; }
public bool State { get; set; }
public virtual Users IdNavigation { get; set; }
}
public partial class CorporateProperty
{
public string Id { get; set; }
public string OrganisationName { get; set; }
public string Website { get; set; }
public bool State { get; set; }
public virtual Users IdNavigation { get; set; }
}
UserControllerClass
// GET: api/Users/5
[HttpGet("{id}")]
public async Task<IActionResult> GetUsers([FromRoute] string id)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var users = await _context.Users.SingleOrDefaultAsync(m => m.Id == id);
if (users == null)
{
return NotFound();
}
return Ok(users);
}
My problem is exactly this; User information is coming but the password and property table information is not coming.
How to modify the following line solves my problem?
var users = await _context.Users.SingleOrDefaultAsync(m => m.Id == id);
based on your code this would also hydrate your CorporateProperty & UseProperty objects, etc.
var user = await _context.Users.Include(user => user.UserProperty).Include
(user => user.CorporateProperty).SingleOrDefaultAsync(user => user.Id == id);
lazy loading doesn't exist yet so you have Eager Loading to play with for now.
Surprised you didn't roll with Identity since this all of this would have been taken care for you especially Passwords... Hope you aren't rolling your own hash for that..
Just add in the custom class / collection objects you need.
you can also check out this link
https://learn.microsoft.com/en-us/ef/core/querying/related-data
I have an entity called Client which fails to insert.
Client inherits from Person inherits from Party.
Here is my model classes:
public class Client : Person
{
public Client()
{
CrimeIncidents = new List<CrimeIncident>();
Reseller = new Reseller();
}
public virtual ICollection<CrimeIncident> CrimeIncidents
{
get;
set;
}
public virtual Reseller Reseller { get; set; }
}
public class Person : Party
{
[CustomValidation(typeof(PartyRoleCustomValidation), "ValidateRSAIDNumber")]
public string IDSocialSecurityPassNum { get; set; }
[DisplayName("Name")]
public string NickName { get; set; }
[DisplayName("Full names")]
public string FullNames { get; set; }
public string Surname { get; set; }
public Gender? Gender { get; set; }
[DisplayName("Date of birth")]
[DataType(DataType.Date)]
public string DOB { get; set; }
}
public class Party
{
public Int64 Id { get; set; }
public virtual PartyRole PartyRole
{
get;
set;
}
//public List<Address> Adresses { get; set; }
public virtual string PostalAddress { get; set; }
[DataType(DataType.PostalCode)]
public virtual string PostalCode { get; set; }
public virtual string PhysicalAddress { get; set; }
[DataType(DataType.PostalCode)]
public virtual string StreetCode { get; set; }
//public List<EmailAddress> EmailAdresses { get; set; }
[DataType(DataType.EmailAddress)]
public virtual string EmailAddress { get; set; }
//public List<ContactNumber> ContactNumbers { get; set; }
[DataType(DataType.PhoneNumber)]
public virtual string CellNumber { get; set; }
[DataType(DataType.PhoneNumber)]
public virtual string PhoneNumber { get; set; }
[DataType(DataType.PhoneNumber)]
public virtual string FaxNumber { get; set; }
}
Here is the unit test, which fails on the assert statement (a manual check in the database confirms the unit test outcome):
[TestMethod]
public void AddClient()
{
JCGunsDbContext db = new JCGunsDbContext();
int initCount = db.Clients.Count();
string guid = Guid.NewGuid().ToString();
Client cl1 = new Client();
cl1.NickName = guid;
cl1.Surname = guid;
cl1.CellNumber = "0123456789";
cl1.EmailAddress = "test" + guid + "#test.com";
db.UserId = "SYSTEM_UNITTESTING";
db.Clients.Add(cl1);
db.SaveChanges();
Assert.IsTrue(db.Clients.Count() > initCount);
}
Why is this insert not working and how do I fix it?
You need to pass the Id the the client if this client is connected to an existed Person.
Otherwise you need to add Person object in the client.Person navigation property.
e.g.
Case you're connecting this client to an existed Person.
Client client = new Client();
client.Id = oldPerson.Id
Case you're adding new client with new Person.
Client client = new Client();
client.Person = new Person(){......}
The problem was the following statement within the constructor of Client:
Reseller = new Reseller();
Reseller is supposed to be optional. Setting a new Reseller instance which did not adhere to it's own annotated validation criteria caused the SaveChanges method to fail without throwing an exception. Removing the statement fixed the problem.