EF5 Object property won't save in a database - object

So I'm creating a simple MVC app that uses the Absence class as a model which holds different properties including an object from the Employee class-another model that holds various properties:
public class Absence
{
public int Id { get; set; }
public string Reason { get; set; }
public int Day { get; set; }
public int Month { get; set; }
public bool isApproved { get; set; }
public int employee_Id { get; set; }
public virtual Employee employee { get; set; }
public Absence()
{
employee = new Employee();
}
}
And I created a controller that has an ActionResult function for the create View:
[HttpGet]
public ActionResult Create()
{
Absence abs = new Absence();
return View(abs);
}
[HttpPost]
public ActionResult Create(Absence abb)
{
Employee emp = database.Employees.FirstOrDefault(z => z.Id == abb.employee_Id);
System.Diagnostics.Debug.WriteLine(emp.Name);
abb.employee.Name = emp.Name;
abb.employee.Surname = emp.Surname;
System.Diagnostics.Debug.WriteLine(abb.employee.Name);
database.Absences.Add(abb);
database.SaveChanges();
return Redirect("/Absence");
}
The idea is to talk to the database find an Employee object with the same EmployeeId and set the name and surname of the employee object of the abb object to be the same and after testing it with the debugger I can see that it works.
However when I want to display all the added absences including the name and surname of their employee like this:
public ActionResult Index()
{
return View(database.Absences.ToList());
}
The name and surname of all the employees don't show.
It seems that all the properties are saved in the database using entity framework except for the Employee object.
Any ideas for how to save it?

Can you try saving the Absences first before updating the employee details? I don't exactly know how your database models are configured and this is just an assumption. The absence that is referencing your employee is not yet available when you are supplying the employee details.
Employee emp = database.Employees.FirstOrDefault(z => z.Id == abb.employee_Id);
database.Absences.Add(abb); //Moved adding here
database.SaveChanges(); // Perform the saving
abb.employee.Name = emp.Name;
abb.employee.Surname = emp.Surname;
database.SaveChanges();

Related

EntityFramework : Invalid column name *_ID1

I am trying to implement DbContext for couple of tables called 'Employee' and 'Department'
Relationship between Employee and Department is many to one. i.e. department can have many employees.
Below are the EntityFramework classes I designed ( CodeFirst approach )
[Table("Employee")]
public class Employee
{
[DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Column("Name")]
public string Name { get; set; }
[Column("Department_ID")]
public int Department_ID { get; set; }
public virtual Department Department { get; set; }
}
[Table("Department")]
public class Department
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[Column("Name")]
public string Name { get; set; }
public virtual ICollection<Employee> Employees { get; set; }
}
While adding Employee record I am getting below exception
"Invalid column name 'Department_ID1'."
I am not sure why EF is referring to Department_ID1. Do I need to add configuration in OnModelCreating method of DbContext?
I am using EF version 6.1.1
I've also gotten this problem in my EF one-many deals where the one has a List of the many property and my mapping didn't specify that property. For example take:
public class Notification
{
public long ID { get; set; }
public IList<NotificationRecipient> Recipients { get; set; }
}
then
public class NotificationRecipient
{
public long ID { get; set; }
public long NotificationID { get; set; }
public Notification Notification { get; set; }
}
Then in my mapping, the way that caused the Exception (the incorrect way):
builder.HasOne(x => x.Notification).WithMany()
.HasForeignKey(x => x.NotificationID);
What fixed it (the correct way) was specifying the WithMany property:
builder.HasOne(x => x.Notification).WithMany(x => x.Recipients)
.HasForeignKey(x => x.NotificationID);
Hi After spending some time I could fix this problem by using ForeignKey attribute on public virtual Department Department { get; set; } property of Employee class.
Please see below code.
[Table("Employee")]
public class Employee
{
[DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Column("Name")]
public string Name { get; set; }
[Column("Department_ID")]
public int Department_ID { get; set; }
[ForeignKey("Department_ID")]
public virtual Department Department { get; set; }
}
This fixed my problem. Are there any other solution to fix this? Using fluent API?
For me, the issue was resolved by removing a (duplicate?) virtual property.
Using the OP's example:
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public int Department_ID { get; set; }
public virtual Department Department { get; set; }
}
public class Department
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<Employee> Employees { get; set; }
}
Turns into:
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public int Department_ID { get; set; }
}
public class Department
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<Employee> Employees { get; set; }
}
In my case I added a virtual property on top of the auto generated property
I fixed it by adding the NotMapped attribute to my property, or you could configure with fluent api
public partial class Control
{
[NotMapped]
public virtual ICollection<Control> Children { get => this.InverseParent; set => this.InverseParent = value; }
}
I had the same error, my issue was the FK was a long but I had it as an int in the model. EF generated a new column because it didn't match types on the FK so it assumed they weren't the same and went ahead with making another one but putting 1 at the end because there was already one with the proper name. Making sure the types matched resolved the issue for me.
This can be fixed simply by putting [NotMapped] annotation on your virtual properties.
public class Employee
{
[ForeignKey("Department")]
public int Department_ID
[NotMapped]
public virtual Department Department { get; set; }
}
And in you modelBuilder:
modelBuilder.Entity<Employee>(entity =>
{
entity.HasOne(e => e.Department);
});
Just flip this around if you want to call by Department.
We use the [NotMapped] annotation so that EF Core will disregard it when looking at your database.

How to get a subset of Users from ASP.NET Identity 2

Using a slightly modified version of the default ASP.NET MVC 5 template (with Individual Accounts), I am trying to get a subset of users based on an intermediary table. I have already built up an administration UI that can return a list of all users, but now I need to limit the set of users returned based on the currently logged in user's access privileges defined in the intermediary table.
Essentially, each user will have access to 1 or more clinics, so there will be one record for each clinic to which they have access.
If the currently logged in user belongs to a given role (e.g., "Clinic Admin"), then they should have the ability to retrieve a list of any users who belong to any of the clinics to which they have access.
Can anyone help point me in the right direction? This is my first Anything.NET application, so please feel free to explain like I'm five. :-)
Thank you in advance for any help you can offer.
Additional information:
Visual Studio 2013 Update 5
Entity Framework 6
MS SQL Server 2008 R2
Here is the intermediary table's class (ClinicUser):
[Table("clinic_users")]
public class ClinicUser
{
[Key]
public virtual ApplicationUser ApplicationUsers { get; set; }
[Required]
public string Id { get; set; }
[Required]
public System.Guid provider_id { get; set; }
[Required]
public System.Guid health_system_id { get; set; }
[Required]
public System.Guid clinic_id { get; set; }
}
Here is my ApplicationUser class:
public class ApplicationUser : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName
{
get { return FirstName + " " + LastName; }
}
[ForeignKey("ClinicUsers")]
public override string Id
{
get
{
return base.Id;
}
set
{
base.Id = value;
}
}
public virtual ClinicUser ClinicUsers { get; set; }
public IEnumerable<SelectListItem> RolesList { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
userIdentity.AddClaims(ClinicClaimsProvider.GetClaims(userIdentity));
return userIdentity;
}
}
In case it wasn't clear, what I'm really trying to do is narrow the list of ApplicationUsers to return only the list of users to which I have access to based on the clinics we have have in common.
If I were writing this as a SQL query, this would be one way to accomplish what I want (I just can't seem to quite get what I want with LINQ):
SELECT *
FROM AspNetUsers au
WHERE Id IN (
SELECT Id
FROM clinic_users
WHERE clinic_id IN (
SELECT clinic_id
FROM clinic_users
WHERE Id = 'CurrentUserId'
)
)
First of all do not user much properties in ApplicationUser class, you can manage user profiles table and connect it with application user class, so you can put lot of information about user in profile table.
Next task is organize table of clinics, branches etc... and asociate application users with them.
Next you have 2 ways:
1. asociate application users with clinics or branches.
or
2. Manage them with roles.
Here is example with Application users:
[Table("Clinics")]
public class Clinic
{
[Key]
public string Id { get; set; }
public virtual ICollection<ClinicUser> ClinicUsers { get; set; }
}
[Table("ClinicUsers")]
public class ClinicUser
{
[Key]
[Column(Order = 0)]
public string ClinicId { get; set; }
[Key]
[Column(Order = 1)]
public string UserId { get; set; }
}
So next you need Other ViewModels to display them hope this help.
UPDATE
// GET: ClinicUsers by Clinic
public async Task<ActionResult> ViewCurrentClinicUsers(string id) // This is clinis ID
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Clinic clinic = await db.clinic.FindAsync(id); // Get Selectedclinic
if (clinic == null)
{
return HttpNotFound();
}
ClinicUsers model = new ClinicUsers() // ClinicUsers model
{
clinic = clinic, // View Currentclinic
ClinicUsers = await db.ClinicUsers.Were(x => x.clinicid == clinic.id)ToListAsync()) // Get Users that asigned to current clinic
};
return View(model);
}
UPDATE 2
And Finaly if you want display clinics were is assigned current loged user
// GET: Clinics by currentuser
public async Task<ActionResult> ViewClinicsWithCurrentUserAccess()
{
var currentuserId = User.Identity.GetUserId(); // This gets currentloged user id
var currentuser = await db.Users.SingleOrDefaultAsync(x => x.Id == myUserId); // This gets currentloged user virtual
return View(await db.Clinics.Were(x => x.clinicuserid == currentuserId).ToListAsync());
}
I solved this a while back, but I thought I had better come back here and update my question with an answer, in case this might help someone else.
I updated my Clinic and ClinicUser classes accordingly:
Clinic.cs
[Table("clinics")]
public class Clinic
{
[Key]
public System.Guid ClinicId { get; set; }
public List<ClinicUser> ClinicUsers { get; set; }
}
ClinicUser.cs
[Table("clinic_users")]
public class ClinicUser
{
[Key, Column(Order = 0)]
public string UserId { get; set; }
[Key, Column(Order = 1)]
public System.Guid ClinicId { get; set; }
[ForeignKey("UserId")]
public virtual ApplicationUser ApplicationUser { get; set; }
[ForeignKey("ClinicId")]
public Clinic Clinic { get; set; }
}
Also, I updated the following excerpt of my ApplicationUser class from this:
[ForeignKey("ClinicUsers")]
public override string Id
{
get
{
return base.Id;
}
set
{
base.Id = value;
}
}
public virtual ClinicUser ClinicUsers { get; set; }
to this:
public List<ClinicUser> ClinicUsers { get; set; }
Finally, in my ApplicationUsersController's Index() action, I was able to use this:
public async Task<ActionResult> Index()
{
if (User.IsInRole("Admin")) return View(await UserManager.Users.ToListAsync());
var userId = User.Identity.GetUserId();
//Get the Ids of the current user's clinics
var userClinics = db.ClinicUsers.Where(cu => cu.UserId == userId).Select(cu => cu.ClinicId).ToList();
//Get all userIds of the user at the current user's clinics
var clinicUserIds = db.ClinicUsers.Where(cu => userClinics.Contains(cu.ClinicId)).ToList().Select(cu => cu.UserId);
var users = UserManager.Users.Where(u => clinicUserIds.Contains(u.Id));
return View(await users.ToListAsync());
}
In essence, if the user has the "Admin" role, then they will get a list of all users in the database. If they aren't, they will only get a list of the users that also belong to the clinics they have in common.
It may not be perfect, but it works. If anyone has any suggestions on how to improve this, I would be glad to hear it.
Again, my thanks to Archil (https://stackoverflow.com/users/4089212/archil-labadze) for his helpful responses.

ServiceStack - [Reference] or [Ignore]?

We have a DTO - Employee - with many (> 20) related DTOs and DTO collections. For "size of returned JSON" reasons, we have marked those relationships as [Ignore]. It is then up to the client to populate any related DTOs that they would like using other REST calls.
We have tried a couple of things to satisfy clients' desire to have some related Employee info but not all:
We created a new DTO - EmployeeLite - which has the most-requested fields defined with "RelatedTableNameRelatedFieldName" approach and used the QueryBase overload and that has worked well.
We've also tried adding a property to a request DTO - "References" - which is a comma-separated list of related DTOs that the client would like populated. We then iterate the response and populate each Employee with the related DTO or List. The concern there is performance when iterating a large List.
We're wondering if there a suggested approach to what we're trying to do?
Thanks for any suggestions you may have.
UPDATE:
Here is a portion of our request DTO:
[Route("/employees", "GET")]
public class FindEmployeesRequest : QueryDb<Employee> {
public int? ID { get; set; }
public int[] IDs { get; set; }
public string UserID { get; set; }
public string LastNameStartsWith { get; set; }
public DateTime[] DateOfBirthBetween { get; set; }
public DateTime[] HireDateBetween { get; set; }
public bool? IsActive { get; set; }
}
There is no code for the service (automagical with QueryDb), so I added some to try the "merge" approach:
public object Get(FindEmployeesRequest request) {
var query = AutoQuery.CreateQuery(request, Request.GetRequestParams());
QueryResponse<Employee> response = AutoQuery.Execute(request, query);
if (response.Total > 0) {
List<Clerkship> clerkships = Db.Select<Clerkship>();
response.Results.Merge(clerkships);
}
return response;
}
This fails with Could not find Child Reference for 'Clerkship' on Parent 'Employee'
because in Employee we have:
[Ignore]
public List<Clerkship> Clerkships { get; set; }
which we did because we don't want "Clerkships" with every request. If I change [Ignore] to [Reference] I don't need the code above in the service - the List comes automatically. So it seems that .Merge only works with [Reference] which we don't want to do.
I'm not sure how I would use the "Custom Load References" approach in an AutoQuery service. And, AFAIKT, the "Custom Fields" approach can't be use for related DTOs, only for fields in the base table.
UPDATE 2:
The LoadSelect with include[] is working well for us. We are now trying to cover the case where ?fields= is used in the query string but the client does not request the ID field of the related DTO:
public partial class Employee {
[PrimaryKey]
[AutoIncrement]
public int ID { get; set; }
.
.
.
[References(typeof(Department))]
public int DepartmentID { get; set; }
.
.
.
public class Department {
[PrimaryKey]
public int ID { get; set; }
public string Name { get; set; }
.
.
.
}
So, for the request
/employees?fields=id,departmentid
we will get the Department in the response. But for the request
/employees?fields=id
we won't get the Department in the response.
We're trying to "quietly fix" this for the requester by modifying the query.SelectExpression and adding , "Employee"."DepartmentID" to the SELECT before doing the Db.LoadSelect. Debugging shows that query.SelectExpression is being modified, but according to SQL Profiler, "Employee"."DepartmentID" is not being selected.
Is there something else we should be doing to get "Employee"."DepartmentID" added to the SELECT?
Thanks.
UPDATE 3:
The Employee table has three 1:1 relationships - EmployeeType, Department and Title:
public partial class Employee {
[PrimaryKey]
[AutoIncrement]
public int ID { get; set; }
[References(typeof(EmployeeType))]
public int EmployeeTypeID { get; set; }
[References(typeof(Department))]
public int DepartmentID { get; set; }
[References(typeof(Title))]
public int TitleID { get; set; }
.
.
.
}
public class EmployeeType {
[PrimaryKey]
public int ID { get; set; }
public string Name { get; set; }
}
public class Department {
[PrimaryKey]
public int ID { get; set; }
public string Name { get; set; }
[Reference]
public List<Title> Titles { get; set; }
}
public class Title {
[PrimaryKey]
public int ID { get; set; }
[References(typeof(Department))]
public int DepartmentID { get; set; }
public string Name { get; set; }
}
The latest update to 4.0.55 allows this:
/employees?fields=employeetype,department,title
I get back all the Employee table fields plus the three related DTOs - with one strange thing - the Employee's ID field is populated with the Employee's TitleID values (I think we saw this before?).
This request fixes that anomaly:
/employees?fields=id,employeetypeid,employeetype,departmentid,department,titleid,title
but I lose all of the other Employee fields.
This sounds like a "have your cake and eat it too" request, but is there a way that I can get all of the Employee fields and selective related DTOs? Something like:
/employees?fields=*,employeetype,department,title
AutoQuery Customizable Fields
Not sure if this is Relevant but AutoQuery has built-in support for Customizing which fields to return with the ?fields=Field1,Field2 option.
Merge disconnected POCO Results
As you've not provided any source code it's not clear what you're trying to achieve or where the inefficiency with the existing solution lies, but you don't want to be doing any N+1 SELECT queries. If you are, have a look at how you can merge disconnected POCO results together which will let you merge results from separate queries based on the relationships defined using OrmLite references, e.g the example below uses 2 distinct queries to join Customers with their orders:
//Select Customers who've had orders with Quantities of 10 or more
List<Customer> customers = db.Select<Customer>(q =>
q.Join<Order>()
.Where<Order>(o => o.Qty >= 10)
.SelectDistinct());
//Select Orders with Quantities of 10 or more
List<Order> orders = db.Select<Order>(o => o.Qty >= 10);
customers.Merge(orders); // Merge disconnected Orders with their related Customers
Custom Load References
You can selectively control which references OrmLite should load by specifying them when you call OrmLite's Load* API's, e.g:
var customerWithAddress = db.LoadSingleById<Customer>(customer.Id,
include: new[] { "PrimaryAddress" });
Using Custom Load References in AutoQuery
You can customize an AutoQuery Request to not return any references by using Db.Select instead of Db.LoadSelect in your custom AutoQuery implementation, e.g:
public object Get(FindEmployeesRequest request)
{
var q = AutoQuery.CreateQuery(request, Request);
var response = new QueryResponse<Employee>
{
Offset = q.Offset.GetValueOrDefault(0),
Results = Db.Select(q),
Total = (int)Db.Count(q),
};
return response;
}
Likewise if you only want to selectively load 1 or more references you can change LoadSelect to pass in an include: array with only the reference fields you want included, e.g:
public object Get(FindEmployeesRequest request)
{
var q = AutoQuery.CreateQuery(request, Request);
var response = new QueryResponse<Employee>
{
Offset = q.Offset.GetValueOrDefault(0),
Results = Db.LoadSelect(q, include:new []{ "Clerkships" }),
Total = (int)Db.Count(q),
};
return response;
}

Breeze doesn't expand TPH entities correctly

Breeze doesn't expand TPH entities correctly.
When using expand in breeze if you are using TPH expand will only work for the first entity, the others properties will be null. If I change the entity not to use inheritances it works fine. I've also tested returning each entity separately in an expand query that also worked fine.
//client side code
var getResidentById = function (id, obs) {
var query = EntityQuery.from('Residents')
.where('id', '==', id)
.expand('user, currentUnit, leases, leases.unit, leases.leaseStatus');
return manager.executeQuery(query).then(function (data) {
if (obs) {
obs(data.results[0])
}
}, queryFailed);
};
//Controler Endpoint
[HttpGet]
public IQueryable<Resident>
{
return _context.Context.UserDetails.OfType<Resident>();
}
//Model
public class UserDetail : EntityBase<int>, IArchivable, IHasPhoto, IDeactivatableEntity, IUpdatable
{
public bool IsArchived { get; set; }
public int LastUpdatedById { get; set; }
public UserProfile LastUpdatedBy { get; set; }
public DateTimeOffset LastUpdatedDate { get; set; }
public string PhotoUri { get; set; }
public bool IsInactive { get; set; }
}
public abstract class UserBelongsToApartmentComplex : UserDetail, IBelongsToApartmentComplex
{
public int ApartmentComplexId { get; set; }
public virtual ApartmentComplex ApartmentComplex { get; set; }
public virtual bool IsInSameComplexAs(IRelatedToApartmentComplex otherEntity)
{
return ApartmentComplexId == otherEntity.ApartmentComplexId;
}
}
public class Staff : UserBelongsToApartmentComplex
{
public string Title { get; set; }
}
public class Admin : UserDetail
{
public string AccessLevel { get; set; }
}
public class Resident : UserBelongsToApartmentComplex
{
public string Pets { get; set; }
public bool HasInsurance { get; set; }
public virtual IList<Lease> Leases { get; set; }
public int? CurrentUnitId { get; set; }
public virtual Unit CurrentUnit { get; set; }
public Resident()
{
Leases = new List<Lease>();
}
}
//response data from sever from endpoint public IQueryable Residents()
[{"$id":"1","$type":"RadiusBlue.Core.Models.Resident, RadiusBlue.Core","Pets":"Sadie, a westie","HasInsurance":false,"Leases":[{"$id":"2","$type":"RadiusBlue.Core.Models.Lease, RadiusBlue.Core","Start":"2012-05-23T00:00:00.000","End":"2013-05-23T00:00:00.000","UnitId":2,"Unit":{"$id":"3","$type":"RadiusBlue.Core.Models.Unit, RadiusBlue.Core","Building":"B","Floor":2,"ModelName":"Tera","RentAmount":2500.00,"NumberOfBeds":1,"NumberOfBaths":3,"UnitName":"102A","IsInactive":true,"Inhabitants":[],"ApartmentComplexId":1,"ApartmentComplex":{"$id":"4","$type":"RadiusBlue.Core.Models.ApartmentComplex, RadiusBlue.Core","Name":"The Stratford","StreetAddress":"100 S Park Ave","City":"Winter Park","StateId":10,"ZipCode":"32792","PropertyManagementCompanyId":1,"IsInactive":false,"TimeZoneId":"Eastern Standard Time","TimeZone":{"$id":"5","$type":"System.TimeZoneInfo, mscorlib","Id":"Eastern Standard Time","DisplayName":"(UTC-05:00) Eastern Time (US & Canada)","StandardName":"Eastern Standard Time","DaylightName":"Eastern Daylight Time","BaseUtcOffset":"-PT5H","AdjustmentRules":[{"$id":"6","$type":"System.TimeZoneInfo+AdjustmentRule, mscorlib","DateStart":"0001-01-01T00:00:00.000","DateEnd":"2006-12-31T00:00:00.000","DaylightDelta":"PT1H","DaylightTransitionStart":{"$id":"7","$type":"System.TimeZoneInfo+TransitionTime, mscorlib","TimeOfDay":"0001-01-01T02:00:00.000","Month":4,"Week":1,"Day":1,"DayOfWeek":"Sunday","IsFixedDateRule":false},"DaylightTransitionEnd":{"$id":"8","$type":"System.TimeZoneInfo+TransitionTime, mscorlib","TimeOfDay":"0001-01-01T02:00:00.000","Month":10,"Week":5,"Day":1,"DayOfWeek":"Sunday","IsFixedDateRule":false}},{"$id":"9","$type":"System.TimeZoneInfo+AdjustmentRule, mscorlib","DateStart":"2007-01-01T00:00:00.000","DateEnd":"9999-12-31T00:00:00.000","DaylightDelta":"PT1H","DaylightTransitionStart":{"$id":"10","$type":"System.TimeZoneInfo+TransitionTime, mscorlib","TimeOfDay":"0001-01-01T02:00:00.000","Month":3,"Week":2,"Day":1,"DayOfWeek":"Sunday","IsFixedDateRule":false},"DaylightTransitionEnd":{"$id":"11","$type":"System.TimeZoneInfo+TransitionTime, mscorlib","TimeOfDay":"0001-01-01T02:00:00.000","Month":11,"Week":1,"Day":1,"DayOfWeek":"Sunday","IsFixedDateRule":false}}],"SupportsDaylightSavingTime":true},"Users":[{"$ref":"1"}],"Groups":[],"IsArchived":false,"ApartmentComplexId":1,"Id":1},"Id":2},"ResidentId":3,"Resident":{"$ref":"1"},"LeaseStatusId":4,"LeaseStatus":{"$id":"12","$type":"RadiusBlue.Core.Models.LeaseStatus, RadiusBlue.Core","Description":"Lost","Id":4},"Id":1},{"$id":"13","$type":"RadiusBlue.Core.Models.Lease, RadiusBlue.Core","Start":"2013-05-24T00:00:00.000","End":"2014-05-24T00:00:00.000","UnitId":1,"Unit":{"$id":"14","$type":"RadiusBlue.Core.Models.Unit, RadiusBlue.Core","Building":"A","Floor":2,"ModelName":"Aqua","RentAmount":2000.00,"NumberOfBeds":2,"NumberOfBaths":1,"UnitName":"101A","IsInactive":true,"Inhabitants":[{"$ref":"1"}],"ApartmentComplexId":1,"ApartmentComplex":{"$ref":"4"},"Id":1},"ResidentId":3,"Resident":{"$ref":"1"},"LeaseStatusId":1,"LeaseStatus":{"$id":"15","$type":"RadiusBlue.Core.Models.LeaseStatus, RadiusBlue.Core","Description":"Active","Id":1},"Id":2}],"CurrentUnitId":1,"CurrentUnit":{"$ref":"14"},"ApartmentComplexId":1,"ApartmentComplex":{"$ref":"4"},"Id":3,"User":{"$id":"16","$type":"RadiusBlue.Core.Models.UserProfile, RadiusBlue.Core","UserName":"vjiawon#gmail.com","FirstName":"Vishal","LastName":"Jiawon","Age":27,"PhoneNumber":"123 456 7890","IsInactive":false,"UserDetail":{"$ref":"1"},"GroupMembers":[],"MaintenanceRequests":[],"Id":3},"IsArchived":false,"LastUpdatedById":1,"LastUpdatedDate":"0001-01-01T00:00:00.000+00:00","IsInactive":false,"CreatedById":1,"CreatedDate":"0001-01-01T00:00:00.000+00:00"}]
I do not doubt that there is a bug in BreezeJS somewhere.
I can report that, at least as of v.1.3.4, Breeze can expand multiple navigation properties of a TPH class ... and not just on the first entity returned.
I just modified the "can navigate to AccountType eagerly loaded with expand" test in inheritanceTests.js in DocCode so that (a) it also expands the Status navigation and (b) the tests are performed on the 3rd entity returned rather than the 1st.
The query is something like this:
var em = newEm(); // clean, empty EntityManager
return EntityQuery.from('bankRootTPHs').take(3)
.expand('AccountType, Status'))
.using(em).execute().then(success).fail(handleFail);
...
function success(data) {
var entity = data.results[data.results.length-1]; // get the last one (the 3rd)
var type = data.query.entityType.shortName;
if (!entity) {
ok(false, "a query failed to return a single " + type);
}
// more tests
// I just set a breakpoint and inspected
// entity.accountType() and entity.status()
// Both returned the expected related entities
}
I see that both the related AccountType and the related Status are available from the entity.
So something else is wrong.
Questions about your Example
First I am compelled to observe that you have a lot of expands. I count 5 related entities. That can hurt performance. I know we're not talking about that but I'm calling it out.
Second, the super class UserDetail is concrete but the intermediate derived class UserBelongsToApartmentComplex is abstract. You have inheritance class hierarchies that go concrete/abstract/concrete. The queried type, Residents is one such class. And a class at every level maps to the "UserDetail" table, yes?
I'm pretty sure we didn't test for that scenario ... which is pretty uncommon. I wasn't even sure that worked! For now I have to take your word for it that EF allows such a construct.
It would seem that BreezeJS is confused about it. We'll take a look.

servicestack ormlite and foreign keys to same table

I have a table of links, and some links will be child links, referencing the parent links ID
however i can not get my head around servicestack ormlite and populating a property of children, will all the child links when getting a list of all links.
Here is my model:
public partial class Navigation
{
[Alias("Id"), AutoIncrement]
public int Id { get; set; }
[Alias("ParentId")]
[Display( Name = "ParentId")]
[References(typeof(Navigation))]
public int? ParentId { get; set; }
[Alias("LinkText")]
[StringLength(50, ErrorMessage = " Must be no more than 50 characters long!")]
[Display( Name = "LinkText")]
public string LinkText { get; set; }
[Alias("Action")]
[StringLength(50, ErrorMessage = " Must be no more than 50 characters long!")]
[Display( Name = "Action")]
public string Action { get; set; }
[Alias("Controller")]
[StringLength(50, ErrorMessage = " Must be no more than 50 characters long!")]
[Display( Name = "Controller")]
public string Controller { get; set; }
[Alias("Area")]
[StringLength(50, ErrorMessage = " Must be no more than 50 characters long!")]
[Display( Name = "Area")]
public string Area { get; set; }
[Alias("Visible")]
[Display( Name = "Visible"),Required(ErrorMessage = " is required" )]
public bool Visible { get; set; }
[Alias("Sequence")]
[Display( Name = "Sequence")]
public int? Sequence { get; set; }
[ForeignKey(typeof(Navigation))]
public virtual ICollection<Navigation> Children { get; set; }
}
any ideas ?
You can do that using inheritance. The parent class will contain a reference to the child class. I had to use it to get which user have created each user. Here is a sample:
public class UserCommon
{
[References(typeof(User))] // Self reference workaround for User ;)
public Guid CreatedBy { get; set; }
}
public class User : UserCommon
{
public Guid Uid { get; set; }
public String Username { get; set; }
public String Password { get; set; }
}
Something you need to pay attention to is to include the Id in the child class not the parent. The table that will be generated is as follow. The foreign key is a self reference
Getting the list of children should be as easy as a simple LINQ query that will fetch all children for a certain parent Guid. CreatedBy is also a property of User becuase of inheritance.
db.Select<User>(q => q.CreatedBy == '734FD814-024D-4795-AFD0-34FECF89A13A');
// Just a sample Guid, you should be able to select
// the Guid you need and insert it here.
Tables in OrmLite are strictly a 1:1 mapping with the underlying db tables.
This means all complex type properties are blobbed into a db text field with the property name, they're never used to auto-map to child relations as you're expecting to do here.
Here's an early answer that shows how you could map many to many relations with OrmLite.

Resources