Unable to save Email property to sql in due to SQL Exception Error :"Null insert not allowed" except property is not null??(ORM-code first) - ef-code-first

I want to generate the email when an employee is created using properties (FirstName and LastName) from the base class:
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DOB { get; set; }
public string Phone { get; set; }
}
public class Employee : Person
{
public Employee()
{
Packages = new List<Package>();
}
public string Email { get =>$"{FirstName[0]}.{LastName}#GTravel.com.au"; }
public IEnumerable<Package> Packages { get; set; }
}
So the output should be something like: J.Smith#GTravel.com.au
I then want to be able to save this employee into a sql database with Person as the Entity/Table and Employee as the discriminator.
using (var gtmsdb = new GTMSDbContext())
{
var newEmployee = new Employee
{
FirstName = "John",
LastName = "Smith",
DOB = new DateTime(1992, 09, 16),
Phone = "03-1234-567"
};
gtmsdb.People.Add(newEmployee);
gtmsdb.SaveChanges();
}
Shows Employee in debugger with email created
When I run the code it creates the employee with the Email in the correct format and everything but when I try saving to the database it returns the error:
SqlException: Cannot insert the value NULL into column 'Email', table
'GTMSDatabase.dbo.People'; column does not allow nulls. INSERT fails.
I also tried saving the Email as a simple {get; set;} and then hard coded the email:
public string Email { get; set; }
var newEmployee = new Employee
{
FirstName = "John",
LastName = "Smith",
DOB = new DateTime(1992, 09, 16),
Phone = "032166702",
Email ="j.smith#gtravel"
};
gtmsdb.People.Add(newEmployee);
gtmsdb.SaveChanges();
But that still returned the same error message.
I also tested with other(new) properties that worked perfectly fine, deleted and retried the migrations, checked in my database for an error there but I am now unsure of the next step to take. There are no references to Email in my Context so is it something that I need to be initialising there?
Edit: I created another smaller scale project where I ran the exact same code and the email saved with no issues:
using (var db = new ETDbContext())
{
var newEmployee = new Employee
{
FirstName = "John",
LastName = "Smith",
DOB = new DateTime(1992, 09, 16),
Phone = "032166702"
};
db.People.Add(newEmployee);
var nc = new Customer
{
FirstName = "Jane",
LastName = "Doe",
DOB = new DateTime(1992, 09, 16),
Phone = "032166702",
Email = "customerEmail"
};
db.People.Add(nc);
db.SaveChanges();
}
I tried to add a Customer just to make sure everything worked but ran into the same problem! Anytime I would create an employee it would save no issues but with the customer it returned the same null reference error

Have you checked before it tries to save if the Email has been set?, If it goes null then the set isn't working, I will do something like below.
var newEmployee = new Employee
{
FirstName = "John",
LastName = "Smith",
DOB = new DateTime(1992, 09, 16),
Phone = "03-1234-567",
Email = '';
};
newEmployee.Email = newEmployee.FirstName.Substring(0,1).ToLower() +
newEmployee.LastName.ToLower() +"#gtravel";

Related

Asp Core, How to create Paging?

I want to use PagingList<T>.CreateAsync() to create PagedList in index view but get below error in line var modelPaging = await PagingList<UserListViewModel>.CreateAsync(model, 10, page);:
can not convert from system.collection.Generic.List<> to system.linq.IorderedQueryable<>
my action code :
[HttpGet]
public async Task<IActionResult> Index(int page = 1)
{
List<UserListViewModel> model = new List<UserListViewModel>();
model = _userManager.Users.AsNoTracking().Select(u => new UserListViewModel
{
Id = u.Id,
FullName = u.FirstName + " " + u.LastName,
Email = u.Email
}).OrderBy(u => u.Id).ToList();
var modelPaging = await PagingList<UserListViewModel>.CreateAsync(model, 10, page);
return View(modelPaging);
}
and UserListViewModel Viewmodel:
public class UserListViewModel
{
public string Id { get; set; }
public string FullName { get; set; }
public string Email { get; set; }
public string RoleName { get; set; }
}
What changes should I make in my code?
I asked another question on this subject here link
The error is pretty clear that tells you CreateAsync needs IOrderedQueryable but you are giving the data already retrieved from database. You should pass the query itself. Remove ToList;
var query = _userManager.Users.AsNoTracking().Select(u => new UserListViewModel
{
Id = u.Id,
FullName = u.FirstName + " " + u.LastName,
Email = u.Email
}).OrderBy(u => u.Id);
var modelPaging = await PagingList<UserListViewModel>.CreateAsync(query, 10, page);
The main purpose of PagingList apply the pagination directly from database instead of in-memory.

Asp.net Mvc and Core , How it works SelectListItem

I have user edit problem in my Edit actions.. when it comes to departmentDropdownlist
When I click a user to edit let say he/she belongs to administration, I want then show
administration in dropdownlist and offcourse below that all departments in the same dropdownlist.
But right now when I click Edit It shows me all departments in Id order.. like I want to add a new user.
I have role dropdown list. tha's woking fine. If the user is Employee .. it shows me first Employee then the rest of Role list.. If the user is Admin , then it shows me Admin
then below that the rest of role list. But when it comes to department it shows me the first departmentname which DeptId = 1 and so on. I tried in both Asp.Net Mvc and Core. Here is my EditUser and EditUserViewModel
[HttpGet]
public async Task<IActionResult> EditUser(string id)
{
EditUserViewModel model = new EditUserViewModel();
model.ApplicationRoles = roleManager.Roles.Select(r => new SelectListItem
{
Text = r.Name,
Value = r.Id
}).ToList();
model.DepartmentNames = context.Departments.Select(s => new SelectListItem
{
Text = s.DeptName,
Value = s.DeptId.ToString()
}).ToList();
if (!String.IsNullOrEmpty(id))
{
ApplicationUser user = await userManager.FindByIdAsync(id);
if (user != null)
{
model.Name = user.Name;
model.Email = user.Email;
model.ApplicationRoleId = roleManager.Roles.Single(r => r.Name == userManager.GetRolesAsync(user).Result.Single()).Id;
model.DeptId = context.Departments.Single(r => r.DeptName == context.Sites.....??????); //How to do here
// ViewBag.DeptId = new SelectList(context.Departments, "DeptId", "DeptName", model.DeptId); // Even like this , shows the first id departmentname
}
}
return PartialView("_EditUser", model);
}
My EditUserViewModel
public class EditUserViewModel
{
public string Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public List<SelectListItem> ApplicationRoles { get; set; }
public string ApplicationRoleId { get; set; }
public List<SelectListItem> DepartmentNames { get; set; }
public int DeptId { get; set; } // I have DeptId too in my AspNetUser table
}
Since the User table has DepartmentId, I don't know why you don't assign model.DeptId to it.
So instead of
model.DeptId = context.Departments.Single(r => r.DeptName == context.Sites.....??????);
You can just assign the DepartmentId from the user table, i.e.,
model.DeptId = user.DepartmentId;
On Razor when you build the dropdown using TagHelper, it should select the correct dropdown option value based on the id.
<select class="form-control" asp-for="DeptId" asp-items="DepartmentNames"></select>

DocumentDb Repository to Query Child Documents Generically

In DocumentDb, is it possible to search for child documents that meet a certain criteria without having to involve the parent class in the query?
BACKGROUND
I'm (trying to start by) using the DocumentDbRepository.cs that is generated for you automatically in the Azure Portal when you create a new Azure Cosmos DB account. However, it's obvious that this was meant merely as a starting point and will require some additional work for individual scenarios.
In a C# Console app (.NET Core) I have a simple parent-child relationship between Company and Employees:
public class Customer
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "location")]
public string Location { get; set; }
[JsonProperty(PropertyName = "employees")]
public List<Employee> Employees { get; set; }
public Customer()
{
Employees = new List<Employee>();
}
}
public class Employee
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "firstName")]
public string FirstName { get; set; }
[JsonProperty(PropertyName = "lastName")]
public string LastName { get; set; }
[JsonProperty(PropertyName = "sales")]
public double Sales { get; set; }
}
In the Document Explorer, I can see that I have one instance of this class structure like so:
{
"id": "7",
"name": "ACME Corp",
"location": "New York",
"employees": [
{
"id": "c4202793-da55-4324-88c9-b9c9fe8f4b6c",
"firstName": "John",
"lastName": "Smith",
"sales": 123
}
]
}
If I wanted to get all Companies that meet a certain criteria, it would be a fairly easy operation using the generated DocumentDbRepository.cs methods:
DocumentDBRepository<Customer>.Initialize();
var customers = DocumentDBRepository<Customer>.GetItemsAsync(p => p.Location.Equals("New York")).Result;
... for reference, the generated GetItemsAsync() from Microsoft method looks like this:
public static async Task<IEnumerable<T>> GetItemsAsync(Expression<Func<T, bool>> predicate)
{
IDocumentQuery<T> query = client.CreateDocumentQuery<T>(
UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId),
new FeedOptions { MaxItemCount = -1 })
.Where(predicate)
.AsDocumentQuery();
List<T> results = new List<T>();
while (query.HasMoreResults)
{
results.AddRange(await query.ExecuteNextAsync<T>());
}
return results;
}
PROBLEM
HOWEVER, if I want to retrieve ONLY EMPLOYEES regardless of the Company they belong to, I'm not sure how to write a method in the repository class that will accomplish this.
First, I think I'll need some sort of type property so I can differentiate what a Customer is versus an Employee (versus other domain class types I may want to also add in the same collection).
Second, I would probably query that using that type property for all queries and not use the DocumentDbRepository.cs methods which seem to only work with root data. In other words, the DocumentDbRepository.cs methods seem to only be concerned with non-hierarchical entities.
But this is where things break down ... given the generic nature of this sample repository class, I can't quite connect the dots in my mind required to query sub-documents / children.
I am merely asking for a nudge in the right direction here. Thank you.
I want to retrieve ONLY EMPLOYEES regardless of the Company
If I understanding correctly, you want to query employees according employees' property from Customer. If it is that case, we could do that with SQL as following, and we just need to change the where <filter_condition> as we want.
SELECT c as employees
FROM c IN Customer.employees
WHERE c.firstName = 'John'
I test with your mentioned document from Azure portal, it works correctly on my side.
The following is the c# demo code:
var endpointUrl = "https://yourdocumentdbname.documents.azure.com:443/";
var authorizationKey = "xxxxx";
var databaseId = "database name";
var collectionId = "collecton name";
var client = new DocumentClient(new Uri(endpointUrl), authorizationKey);
var sql = "SELECT c as employee FROM c IN Customer.employees WHERE c.firstName = 'xx'";
var collection = client.CreateDocumentCollectionIfNotExistsAsync(
UriFactory.CreateDatabaseUri(databaseId), new DocumentCollection
{
Id = collectionId
}).Result.Resource;
var query = client.CreateDocumentQuery(collection.SelfLink, sql).AsDocumentQuery();
while (query.HasMoreResults)
{
var documents = query.ExecuteNextAsync().Result;
//do something
}

Query a Model regarding its ICollection<> asp.net mvc

Using EntityFramework6 Code-First mvc 5 I have the following model:
Course
public class Course
{
public Course()
{
EnrolledStudentsEmails = new HashSet<ApplicationUser>();
}
[Key]
public string Id { get; set; }
public string UserName{ get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ICollection<ApplicationUser> EnrolledStudentsEmails { get; set; }
I'm trying to query the following to IPagedList(Courses)
var model =
(from c in db.Courses
where searchTerm == null ||
c.Id.StartsWith(searchTerm) ||
c.Name.StartsWith(searchTerm)
select new
{
Id = c.Id,
Name = c.Name,
Description = c.Description,
UserName = c.UserName
}).AsEnumerable().Select(c => new Course
{
Id = c.Id,
Name = c.Name,
Description = c.Description,
UserName = c.UserName
}).ToPagedList(page, 10);
What should be the type of the ICollection EnrolledStudents if I want to use the AspNetUsers table generated when using user authentication?
The upper LINQ gets me All the courses in the database.
how can I get the courses that example#123.com is enrolled in?
Is it possible using my model? should I change my model?
Knowing that I can access the Email using:
User.Identity.Name
If your existing code works, your models are correct and you just want to filter by a known email, just use your collection:
var emailFilter = "example#123.com";
var model =
(from c in db.Courses
where (searchTerm == null ||
c.Id.StartsWith(searchTerm) ||
c.Name.StartsWith(searchTerm)) &&
c.EnrolledStudentsEmails.Any(e => e.Email == emailFilter)
select new
{
Id = c.Id,
Name = c.Name,
Description = c.Description,
UserName = c.UserName
}).AsEnumerable().Select(c => new Course
{
Id = c.Id,
Name = c.Name,
Description = c.Description,
UserName = c.UserName
}).ToPagedList(page, 10);

Entity Framework : adding record with related data

I have a very simple Situation with 2 tables
public class Movie
{
[Key]
public Guid ID { get; set; }
public string Name { get; set; }
public byte[] Hash { get; set; }
public int GenreID{ get; set; }
[ForeignKey("GenreID")]
public virtual Genre genre{ get; set; }
}
and
public class Genre
{
public int ID { get; set; }
public string Name { get; set; }
}
Now, in an import sequence I want to create new movies and link the Genre with the existing entries in the Genre table or create new Genre entries if they don't exist.
Movie m = new Movie();
m.ID = Guid.NewGuid();
IndexerContext db = new IndexerContext();
var genre = db.Genre.Where(g => g.Name== genreValue).FirstOrDefault();
if(genre!= null)
{
m.GenreID= genre.GenreID;
}
else
{
genre= new Genre();
genre.Name = genreValue;
db.Genres.Add(genre);
var genreCreated= db.Genre.Where(g => g.Name== genreValue).FirstOrDefault();
m.GenreID= genreCreated.GenreID;
}
Now the problem is, it doesn't work. The last line fails because genreCreated is null.
Plus I think I must doing it wrong - it can't be that difficult in Entity Framework.
can anyone help me?
db.Genres.Add(genre);
This does not send insert statement to database - this instructs entity framework that new record should be inserted when saving changes. Genre will be saved (and created id available) after you call db.SaveChanges(); As for now, you do not have save call, so genreCreated is null.
In your situation - fix is simple, you do not need to select genreCreated from db. Just setting m.Genre to new value should do the job
Movie m = new Movie();
m.ID = Guid.NewGuid();
IndexerContext db = new IndexerContext();
var genre = db.Genre.Where(g => g.Name== genreValue).FirstOrDefault();
if(genre! = null)
{
m.GenreID = genre.GenreID;
}
else
{
genre = new Genre();
genre.Name = genreValue;
m.Genre = genre;
}
db.SaveChanges(); //m.GenreID will automatically be set to newly inserted genre
After the add statement you need to save it:
Try
genre= new Genre();
genre.Name = genreValue;
db.Genres.Add(genre);
db.SaveChanges();

Resources