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.
Related
I want to add two properties from the city model:
after migration this error shows up:
Unable to determine the relationship represented by navigation
'City.Orders' of type 'ICollection'. Either manually configure
the relationship, or ignore this property using the '[NotMapped]'
attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
here is my code :
public class Order
{
public virtual City FromCity { get; set; }
public virtual City ToCity { get; set; }
}
public class City
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Order> Orders { get; set; }
}
I suppose your model is more complicated than just FromCity and ToCity because I don't think it's a good idea to store such information in a different table. Yet, You can use inheritance in this case.
The table-per-hierarchy (TPH) pattern is used by default to map the inheritance in EF. TPH stores the data for all types in the hierarchy in a single table.
However, for your scenario, you can have a base class that holds all related attributes.
public class CityBase
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
}
Then suppose you need two entities as per your scenario:
public class FromCity : CityBase
{
public virtual ICollection<Order> Orders { get; set; } = null!;
}
public class ToCity : CityBase
{
public virtual ICollection<Order> Orders { get; set; } = null!;
}
And the order entity:
public class Order
{
public int Id { get; set; }
public string OrderTitle { get; set; } = string.Empty;
public virtual FromCity FromCity { get; set; } = null!;
public virtual ToCity ToCity { get; set; } = null!;
}
This approach can solve your problem with a One-to-Many relationship between Orders and FromCity, ToCity as per below diagram:
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();
}
I have a little problem when I try to save an item in my DB using EntityFramework.
My classes looks like:
public partial class Site
{
public int Id { get; set; }
public string Name { get; set; }
public string LongName { get; set; }
public string Adress { get; set; }
public City City { get; set; }
public Country Country { get; set; }
public string VATNumber { get; set; }
}
public class Country
{
public int CountryId { get; set; }
public string Name { get; set; }
public string IsoCode { get; set; }
}
And when I try to create a new site in my controller it works, but when I try to add a link to an existing Country :
if (SiteProvider.GetSiteByName(Site.Name) == null)
{
Site.Country = CountryProvider.GetCountryById(1);//it's working, i see the link to the right country
SiteProvider.Create(Site);
}
public static void Create(Site Site)
{
using (MyDBContext Context = new MyDBContext())
{
Context.Site.Add(Site);
Context.SaveChanges(); //here is the problem
}
}
I got this error:
SqlException: Cannot insert explicit value for identity column in
table 'Country' when IDENTITY_INSERT is set to OFF
Thanks in advance for your help.
Add CountryId property to Site class and when adding a new Site set CountryId instead of Country property
public int CountryId { get; set; }
[ForeignKey("CountryId")]
public Country Country{ get; set; }
You have a slight issue with your use of contexts here. You have used one DBContext instance to load the country (where this country object will be tracked) and then a second DBContext to save the site (where the first country object is a property).
It is preferable to perform all your operations for a single unit of work by using one DB context (that would be shared between your classes) and the responsibility for disposing of it to be handled outside your repository layer.
Quite new with LINQ. I am wondering how I would be able to achieve this.
I have the following table classes defined:
public partial class Cars
{
public long ID { get; set; }
public string CarName { get; set; }
public long CarModelID { get; set; }
public virtual CarModel CarModel { get; set; }
}
public partial class CarModel
{
public long ID { get; set; }
public string ModelName { get; set; }
public long StockID { get; set; }
}
public partial class Stock
{
public long ID { get; set; }
public string StockName { get; set; }
}
There's also a defined extension for the class Cars (Cars.extension.cs):
public partial class Cars
{
public List<Stock> StockList { get; set; }
}
I am trying to get all the Cars, CarModel and (List of) Stocks via the following query:
var query = (from cars in Context.Cars.Include("CarModel").Include("StockList")
select cars).FirstOrDefault();
It is giving me an error:
"A Specified Include Path is not Valid. The Entity Type Cars does not declare a Navigation Property with the name 'StockList'"
How would I be constructing my LINQ query such it would include possibly the list of Stocks based on a CarModel based off Cars?
The Include method is adhering to FluentAPI principles, that means further Include() calls are still in the context of the parent entity (Cars) and not in the previously included CarModel.
What you need is:
Cars.Include("CarModel.StockList")
Or
Cars.Include(x => x.CarModel.StockList)
I am using Entity Framework Database First, but I would like to replicate the following behavior from the Code First paradigm:
In Entity Framework Code First, you can do something along these lines:
public class Thing
{
public int ID { get; set; }
ICollection<Stuff> Stuffs { get; set; }
}
public class Stuff
{
public int ID { get; set; }
ICollection<Thing> Things { get; set; }
}
And the database will generate and Associative table to represent the many to many relationship.
I'm using Database First with a legacy database. I pulled in the entities and it included the associative table representing a many-to-many relationship between two of our tables.
Since the associative table is included as an entity, the navigation properties are as such:
public class Thing
{
public int ID { get; set; }
public ICollection<ThingStuff> ThingStuffs { get; set; }
}
public class ThingStuff
{
public int ThingID { get; set; }
public int StuffID { get; set; }
ICollection<Thing> Things { get; set; }
ICollection<Stuff> Stuffs { get; set; }
}
public class Stuff
{
public int ID { get; set; }
public ICollection<ThingStuff> ThingStuffs { get; set; }
}
So to navigate, I have to:
var stuff = Thing.ThingStuffs.Select(ts => ts.Stuff);
Instead of:
var stuff = Thing.Stuffs;
So The Question Is:
Is there any way to drop the entity representing the association (ThingStuff) and tell EntityFramework about the existing table to create the many-to-many navigation properties?
Wouldn't it be better if you map your composite keys, as stated in the fluent api documentation? http://msdn.microsoft.com/en-us/data/jj591617.aspx