Breeze - self referencing entity - entity-framework

i get some problem using Breeze to execute queries via my ASP.NET web api application.
Here is my entity definition that i want to request on :
[Serializable]
[DataContract]
public class Subject
{
public Subject()
{
Subjects = new List<Subject>();
}
[DataMember]
public int Id { get; set; }
[DataMember]
public String Name { get; set; }
[DataMember]
public Subject Parent { get; set; }
[DataMember]
public IList<Subject> Subjects { get; set; }
}
and here is the query in my datacontext.js file
var query = EntityQuery.from("Subjects");
manager.executeQuery(query)
.then(function (data) {
// do something with data.results
})
.fail(function (error) {
});
but the query always fails with an error saying "expected object"
All other queries on other "simple" entities works fine.
If i remove the properties "Parent" and "Subjects" from my Subject Entity,
the query works.
Does anyone have an idea ?
Thanks !

Breeze needs a foreign key in order to fix up the relations between entities and you're missing it in your Subject class definition:
[DataMember]
public System.Nullable<int> ParentId { get; set; }
Or, if you are using non-conventional naming, be sure to add the ForeignKey tag to the navigation:
[DataMember]
[ForeignKey("FKParentId")]
public Subject Parent { get; set; }
You could also define it via Fluent Interface. You will find more on that at http://msdn.microsoft.com/en-us/data/hh134698.aspx.

Thanks !
i added :
[DataMember]
public System.Nullable<int> ParentId { get; set; }
and it works fine now.

Related

How to map DTO object to entity when some properties are missing in the DTO?

I am receiving PostDTO object in the controller and I am mapping it to Post entity and updating database. The problem occurs because PostDTO doesn't have Status property and Post entity does have Status property, so when I map PostDTO to Post, Post.Status becomes null. I don't want it to be null, I want it to stay unaffected in database. I could retrieve post from database and manually map Status property but is there better solution for this?
public class PostDTO
{
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public bool Urgent { get; set; }
}
public class Post
{
public long Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public bool Urgent { get; set; }
public string Status { get; set; }
}
var post = _mapper.Map<Post>(postDto); //here post.Status becomes null
You could either use an approach like this to ensure the field isn't updated:
https://stackoverflow.com/a/10271910/84206
OR you can first GET the entity from the database, so that the Status is populated from the database, then apply the DTO changes to the entity.
There's other approaches, but they can't really be applied with EF.

OData v4 Expanding Multiple One-Many

I'm creating an ASP.NET Core 3.1 Web API using OData v4.
I just made a GitHub repo here containing the entire solution, even the database project with dummy data.
Some blogs helped me along the way:
Experimenting with OData in ASP.NET Core 3.1
Supercharging ASP.NET Core API with OData
I've successfully created 3 basic endpoints that can be queried (Countries, Cities and Customers).
The Country and City endpoints work as expected, it is the Customer endpoint that causes some issues on $expand.
The Customer model looks like this (please note that I am currently using domain entities instead of DTO's because I want to get everything working smoothly first, before projecting them to DTO's):
public abstract class AppEntity : IAppEntity
{
[Key]
public int Id { get; set; }
}
public class Customer : AppEntity
{
public string Name { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public virtual City City { get; set; }
public string VAT { get; set; }
public virtual List<CustomerEmailAddress> EmailAddresses { get; set; }
public virtual List<CustomerNote> Notes { get; set; }
}
With the following models acting as navigation properties:
public class CustomerEmailAddress : AppEntity
{
public Customer Customer { get; set; }
public string EmailAddress { get; set; }
public bool IsPrimary { get; set; }
}
public class CustomerNote : AppEntity
{
public Customer Customer { get; set; }
public DateTime DateTime { get; set; }
public string Message { get; set; }
}
Most of my queries are successful:
Just the collection: https://localhost:44309/api/customer
Expanding the City: https://localhost:44309/api/customer?$expand=City
On of the one-many relationships: https://localhost:44309/api/customer?$expand=Notes
But as soon as I try to expand 2 or more one-many properties or expand all (?$expand=*), I get an exception:
System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index')
Any clue where this exception might be coming from?
My EdmModel is defined as:
IEdmModel GetEdmModel()
{
var odataBuilder = new ODataConventionModelBuilder();
odataBuilder.EntitySet<Country>("Country");
odataBuilder.EntitySet<City>("City");
odataBuilder.EntitySet<Customer>("Customer");
return odataBuilder.GetEdmModel();
}

Using OData with model inheritance cause missing property error

I got this error in my OData with asp.net core implementation during the runtime :The EDM instance of type '[XXX.Asset Nullable=True]' is missing the property 'externalId'.
The problem appear when I try to access the odata endpoint with the expand query: "/odata/v1/precinct?$expand=assets". It seems happening because I put the "ExternalId" property in my base class, its not happening if I put that property in the "Asset".
Below is my recent codes:
public abstract class Entity
{
public int Id { get; set; }
public string ExternalId { get; set; }
}
public class Precinct : Entity
{
public string Name { get; set; }
public string Description { get; set; }
public virtual IEnumerable<Asset> Assets { get; set; }
}
public class Asset : Entity
{
public string Name { get; set; }
public string Description { get; set; }
}
and here is my model configuration for ODATA
public class AssetModelConfiguration : IModelConfiguration
{
public void Apply(ODataModelBuilder builder, ApiVersion apiVersion)
{
var org = builder.EntitySet<Asset>("asset").EntityType;
org.HasKey(x => x.ExternalId);
org.Ignore(x => x.Id);
}
}
The strange thing is if I put that ExternalId in "Asset" class, it is working. Id property is the primary key while the "ExternalId" is marked as AlternateKey in the DBModel configuration.
am I missing something in my odata configuration? already tried many things but couldn't find a good answer. Any help would be appreciated!

AutoMapper Queryable Extensions with Entity Framework - how to get OUTER joins?

I have a Job entity with an optional Contract child entity (using Entity Framework)
public class Job
{
public string Title { get; set; }
public Guid? ContractId { get; set; }
public virtual Contract Contract { get; set; }
}
public class Contract
{
public DateTime StartDate{ get; set; }
}
I have the following DTO
public class JobDto
{
public string Title { get; set; }
public DateTime ContractStartDate { get; set; }
}
I project to the DTO using AutoMapper Queryable extensions.
c.CreateMap<WorkTask, WorkTaskDtoLite>();
var jobDtos = _context.Jobs.ProjectTo<JobDto>().ToList();
Then this generates INNER joins, so does not return any JobDtos where there is no Contract. I need OUTER joins...
I'm really not sure how to fix this. I have referred to https://github.com/AutoMapper/AutoMapper/wiki/Queryable-Extensions but this does not seem to address this basic issue.
Any help appreciated!
UPDATE
Thanks all but seems to be an underlying issue with Entity Framework Core RC1.
See bug report here:
https://github.com/aspnet/EntityFramework/issues/3186
With suggested work-around here:
https://github.com/aspnet/EntityFramework/commit/c4e44471b6f41f96d37b1acfbbb4cc97cd11ee89

How Do I Resolve "A specified Include path is not valid"?

I have a parent-child relationship setup that is fairly basic. The end result is that I want to be able to return the resulting tables as JSON through ASP.NET MVC WebAPI. I am using Entity Framework 5.0 beta 2.
I can demonstrate the error I'm running into with a simple example. Given the classes Category and Product with the corresponding data context:
public class Category
{
public int CategoryId { get; set; }
public string Title { get; set; }
public virtual IEnumerable<Product> Products { get; set; }
}
public class Product
{
public int ProductId { get; set; }
public string Title { get; set; }
public virtual Category Category { get; set; }
public virtual int CategoryId { get; set; }
}
public class ProductDataContext : DbContext
{
public DbSet<Category> Categories { get; set; }
public DbSet<Product> Products { get; set; }
}
When I try to run a query that includes the products I get the following error:
A specified Include path is not valid. The EntityType 'FooAndBar.Category'
does not declare a navigation property with the name 'Products'.
The statement to fetch is pretty straightforward:
var everything = dc.Categories
.Include(c => c.Products);
What is the correct way to setup the columns and/or the query so that the Products are included with the Categories?
Child collection properties must be declared as anICollection<T>, not anIEnumerable<T>.
Also, you do not need to explicitly add a CategoryId field to the child class; EF will create that automatically in the database.