Entity Framework - The property cannot be configured as a navigation property - entity-framework

I'm defining two entities like the following, but a strange behavior is occurring:
[Table("ClientTypes", Schema="dbo")]
public ClientType {
[Key]
public int Id { get; set; }
public string Name { get; set; }
}
[Table("Clients", Schema="dbo")]
public Client {
[Key]
public long Id { get; set; }
[ForeignKey("ClientTypeId")]
public int ClientTypeId { get; set; }
public virtual ClientType ClientType { get; set; }
}
I'm getting the ClientTypeId property filled with some value, but the ClientType object is filled with nothing. Can someone help me with this?
Thank you all!

The ForeignKey attribute as you have it is on the wrong property.
The annotation may be placed on the foreign key property and specify the associated navigation property name, or placed on a navigation property and specify the associated foreign key name.
- source
[ForeignKey("ClientTypeId")] should decorate public virtual ClientType ClientType instead,
or change it to [ForeignKey("ClientType")] and leave it where it is.

Are you eagerly loading the value?
var clients = context.Clients.Include("ClientType").ToList();

When selecting the Client you have to Include the client type
Client cli = (from c in db Clients.Include("ClientType")//or the name of the property
select c).First();
This translates to a left join and selects the data for Client and ClientType.
If you skip the Include the EF will select the data only for the client when execute the statement.
As Mike said if the context is still available the property will be lazy loaded when you access it.

Related

Entity Framework 7 Include() not working as expected

EF7 fills contained navigation properties even when not requested. For example, I have the below entities.
public class Employee
{
public int EmployeeId { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
public int DepartmentId { get; set; }
public Department Department { get; set; }
}
public class Department
{
public int DepartmentId { get; set; }
public string Name { get; set; }
public ICollection<Employee> Employees { get; set; }
}
My fetch query is as below.
ctx.Employees.Where(e => e.Gender == "Male").Include(e => e.Department)
I get Department property of Employee object filled – which is as expected as I have an Include for Department. I find that Department.Employees is also filled but partially (only with male employees). I have not specified an Include for Department.Employees, but it is still getting populated. Is this behavior by design? Is there any way to avoid fetching Department.Employees in this scenario?
I am using EF7 NuGet package with version 7.0.0-rc1-final.
That is the normal behavior of EF. When you execute your query, all the entities you load is going to be attached to your context. So, EF is not executing another query and loading Department.Employees partially, those employees were loaded earlier when you execute your query. In summary, when you consult Department.Employees navigation property, EF is going to fill that property with the employees that you load with your query filtering by Gender.
Update:
As I pointed out in my comment above, Lazy Loading is not supported in EF7. If you want to avoid that Json.NET serializes that property, you can use the attribute JsonIgnore over that property or you can create a custom class (DTO) to project your query and fill only the properties that you need. I also recommend take a look to Automapper if you decide to use this last solution.

EF7 Scaffolding not creating columns

I have a model that looks like this:
public class Order
{
// removed irrelevant other properties
public Guid Id { get; set; }
public Address BuyerAddress { get; set; }
public Address SellerAddress { get; set; }
}
public class Address
{
public Guid Id { get; set; }
public string Street { get; set; }
public Order Order { get; set; }
}
In the DbContext I hooked them up like this:
entityTypeBuilder.HasOne(x => x.BuyerAddress).WithOne(x => x.Order).IsRequired(false);
entityTypeBuilder.HasOne(x => x.SellerAddress).WithOne(x => x.Order).IsRequired(false);
When I run
dnx ef migrations add Foo
dnx ef database update
The table is being created with some of the properties, but other properties, like the SellerAddress are missing (the BuyerAddress is being created fine though).
The same problem for other entities, such as User <-> BankAccount which is a 1:1 relationship that is defined as entityTypeBuilder.HasOne(x => x.BankAccount).WithOne(x => x.User).IsRequired(false);
Does anyone know what's up? I'm using Entity Framework 7.0.0-rc1-final. The issue is driving me crazy.
I fixed the problem. First I had foreign key properties, so my models looked like this:
public Order Order {get;set;}
public Guid OrderId {get;set;}
I didn't like this, and it resulted in duplicate columns in the database, so I removed the [EntityName]Id properties from my model. But because of this, EF got all confused could not longer figure out what I was trying to do. So for all 1:1 relationships I simply removed the navigation property on one side of the equation (so now Order has a reference to an Address, but Address no longer has a navigation property back to Order). This solved the problem.
So in case of the sample code in my question, I removed the Order property from Address.

Entity Framework with Proxy Creation and Lazy Loading disabled is still loading child objects

I'm having some issues with the Entity Framework using POCOs and I hope someone can tell me at a high level if the behaviour I'm seeing is expected or I need to dig deeper into why it's happening.
I have a class Customer and another CustomerType, so Customer has a property Type (of type CustomerType indicating the type) and CustomerType has property Customers which is a collection of Customers (All Customers that have that type) So these are basically the Navigation properties on both ends of an association, resulting in POCO code something like:
public partial class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public int TypeId { get; set; }
public CustomerType Type { get; set; }
}
public partial class CustomerType
{
public CustomerType()
{
this.Customers = new HashSet<CustomerType>();
}
public int Id { get; set; }
public string TypeName { get; set; }
public virtual ICollection<Customer> Customers { get; set; }
}
I have turned off Proxy creation and LazyLoading (i.e. both DbContext.Configuration.ProxyCreationEnabled=false and DbContext.Configuration.LazyLoadingEnabled=false) because they make Serialization a pain.
As expected when I get instances from the Customer set, the Type property on them is null by default.
But if I get instances from the Customer set with a .Include("Type") not only is it loading the Type properties, but it's also loading the children - i.e. the collection of Customers on each of these.
Is this expected?
It is semi expected. The Include extension affects the SQL that is run. Those CustomerTypes that ARE loaded (by virtue of being included in the Customer query) will be built into the object tree according to the CustomerType.ParentId column.
So if by some fluke both a parent and a child is loaded in the same query, the child will be stuffed into the parent.

How do I include an unmapped field in a POCO class

I'm new to the EF and am just experimenting. Can someone tell me if the following is possible. Given a (product) table in the DB like so:
Id Cost DescriptionFK
-- ---- -------------
? ? ?
I want the corresponding POCO class (entity) to appear like:
public class Product
{
public int Id { get; set; }
public decimal Cost { get; set; }
public string Description { get; }
}
Note that the "Description" in the class is a read-only string (no setter), but it's a key in the table. I'm calling a stored procedure to pull this off (converting the key to its corresponding string and returning the above class), but if I now do something like:
// ...
product.Cost = 20;
myContext.SaveChanges();
I get an exception complaining that there's no mapping for the "Description" string. I removed the mapping because it's read-only and I don't need to include the "DescriptionFK" in the class itself. Is there some way to pull this off (POCO only). Thanks very much.
If you are just looking to have the Description property as a calculated field, add [NotMapped] to your the property to explicitly exclude it and then generate the database:
public class Product
{
public int Id { get; set; }
public decimal Cost { get; set; }
[NotMapped]
public string Description { get; }
}
AFAIU, it is not possible.
"You always need at least one navigation property to create a foreign key constraint in the database."
EF Code First foreign key without navigation property

Exact purpose of Entity Framework navigation properties

please have a look at the following POCOs:
public class Country
{
[Key]
public Guid ID { get; set; }
[Required]
public virtual Currency Currency { get; set; }
}
public class Currency1
{
[Key]
public Guid ID { get; set; }
public virtual ICollection<Country> Countries { get; set; }
}
public class Currency2
{
[Key]
public Guid ID { get; set; }
}
I am not exactly sure what I need navigation properties like the ICollection in Currency1 for. If it comes to EF CodeFirst I see no difference in the database structure created. The tables of Currency1 and Currency2 look pretty much the same to me. So why or when does it make sense to add this extra property?
Of course, just thinking of the POCOs I understand that I can't access any countries from a Currency2 object. For example:
var a = currency1.Countries; // works fine
var b = currency2.Countries; // does not even compile
But is this the only difference? In other words: If I do not need to access countries from a Currency2 object, there is no need to add a corresponding navigation property in the Currency2 class for the purposes of EF? Kind of confused here...
Navigation properties are used either for direct access (as you described) or in linq-to-entities queries. If you don't plan to use it you can remove it from your model. Just be aware that you need a navigation property on at least one side to be able to model database realation using the code first approach.