EF: Declaring Many-to-Many relationship in attributes - entity-framework

Many to many relationships can be declared like this in fluent-API.
modelBuilder.Entity<Course>()
.HasMany(t => t.Instructors)
.WithMany()
I would rather if there were certain attributes that could do the same in my domain model.
Are there such attributes somewhere in the framework, or can I make some of my own that can affect EF behavior when it generates the database?

I've assumed your model, try below and see if it works.
public class Course
{
[InverseProperty("Courses")] //add this attribute
public ICollection<Instructor> Instructors { get; set; }
//other properties..
}
public class Instructor
{
[InverseProperty("Instructors")] //add this attribute
public ICollection<Course> Courses { get; set; }
//other properties..
}
that way you tell entity framework to look for what property to map with in the Course model for Instructor.
Moreover, you don't even need to define that way. but In case you have more than one property of type Course in Instructor or vice-versa, you will need to point out correctly which is mapped to what.
Still, using fluent API is much better and scalable and manageable

You don't need any attributes for it. If you declare ICollection<T> in each entity, EF will create many to many relationships by convention. See here.

Related

Can EF Core configure a "real" One-To-One relation where both ends are required?

The EF Core documentation about One-To-One relations says: "When configuring the relationship with the Fluent API, you use the HasOne and WithOne methods." A closer look shows that this configures One-To-ZeroOrOne or ZeroOrOne-To-ZeroOrOne relations depending on whether IsRequired is used or not. Example:
public class ParentEntity
{
public Int64 Id { get; set; }
public ChildEntity Child { get; set; }
}
public class ChildEntity
{
public Int64 Id { get; set; }
public ParentEntity Parent { get; set; }
}
The derived context class contains:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<ParentEntity>().HasOne(p => p.Child).WithOne(d => d.Parent)
.HasForeignKey<ChildEntity>("ParentFk").IsRequired();
}
With this configuration, context.SaveChanges fails after context.Add(new ChildEntity()) as expected (with SqlException: Cannot insert the value NULL into column 'ParentFk' ... because of IsRequired) but succeeds after context.Add(new ParentEntity()) and context.Add(new ChildEntity() { Parent = new ParentEntity() }), i.e., the ParentEntity-ChildEntity relation is One-To-ZeroOrOne. In other words: the parent of a child is required, the child of a parent is optional.
Is there a way to configure a "real" One-To-One relation where both ends are required?
Maybe this cannot be enforced within the database. But can it be enforced by EF Core? (BTW: It can be enforced by EF6.)
Is there a way to configure a "real" One-To-One relation where both ends are required?
At the time of writing (EF Core 2.1.2), the answer is (unfortunately) negative.
The Required and Optional Relationships section of the documentation says:
You can use the Fluent API to configure whether the relationship is required or optional. Ultimately this controls whether the foreign key property is required or optional.
There is also a closed issue EF Core 2: One to One Required Not Being Enforced (also Navigation no longer needed?) #9152 asking the same question, and part of the response is:
when a relationship is made "Required" it means that a dependent entity cannot exist without an associated principal entity. This is done my making the FK non-nullable--i.e. the FK value must reference some principal entity.
However, it says nothing about the principal entity existing without the dependent. This is always possible because there isn't really any way to restrict it when working with partially loaded graphs. (This was the same with the old stack, although there were some situations where the state manager would, almost arbitrarily, stop certain things happening.) With stronger semantics applied to aggregates that limit partially loading of graphs it may be possible to enforce such a restriction in the future, but that isn't done yet.

add several references to the same record in navigation property

In my EF 6 Model First application, I have an entity with a many-to-many navigation property to another entity. In the first entity, I need to add several references to the same record in navigation property.
The first entity is a “saleslistItem” and the second entity is “warehouseItem”. Normally there will be a one-to-one relationship here, but exceptionally there will be some bundles where one “saleslistItem” contains several “warehouseItems”. “WarehouseItem” can also be included in several “salesListItems”. At the end of the project, my customer says, testing it, that “saleslistItem” must be able to consist of several “WarehouseItems” of the same kind (like two boxes of smoked ham).
These data is used several places in my code. (ie. doing a sale removes items from the warehouse) If I could just add several the same reference, my code would work without any modifications. But in the implementation of the navigation property the “hashtable”-collection is used, and this collection requires unique entries. Is there a workaround here? Performance is irrelevant as the data amount is small.
If there are no such workaround, is it possible to store values together with the instance of navigation property? Maybe it is implemented as a field in the join-table???
Any other suggestions?
Need a solution so the customer pays the last part of the bill!
So you currently have a 1:1 from SalesListItem toWarehouseItemvia a ForeignKey inSalesListItem`? Sounds like you need:
public class SalesListItem
{
public virutal ICollection<SalesListWarehouseItem> WareHouseItems { get; set; }
}
public class SalesListWarehouseItem
{
public virtual SalesListItem Parent{ get; set; }
public virtual WarehouseItem WarehouseItem { get; set; }
public int Quantity { get; set; } // maybe double?
}

Want Entity Framework 6.1 eager loading to load only first level

I am not sure I am approaching wrong way or it is a default behaviour but it is not working the way I am expecting ...
Here are two sample classes ...
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Department Department { get; set; }
}
Second one is Department
public class Department
{
public string Name { get; set; }
public List<Person> People { get; set; }
}
Context Configuration
public MyDbContext() : base("DefaultConnection")
{
this.Configuration.ProxyCreationEnabled = false;
this.Configuration.LazyLoadingEnabled = false;
}
public DbSet<Person> People { get; set; }
public DbSet<Department> Departments { get; set; }
I am try to load people where last name is from 'Smith'
var foundPeople
= context
.people
.Where(p => p.LastName == "Smith");
Above query load foundPeople with just FirstName and LastName no Department object. It is a correct behaviour as my LazyLoading is off. And that was expected as well.
Now in another query with Eager loading Department,
var foundPeople
= context
.people
.Where(p => p.LastName == "Smith")
.Include(p => p.Department);
Above query loads foundPeople with FirstName, LastName, Department with Department->Name as well as Deparment->People (all people in that department, which I dont want, I just want to load first level of the Included property.
I dont know is this an intended behaviour or I have made some mistake.
Is there any way to just load first level of Included property rather then complete graph or all levels of included property.
Using Include() to achieve eager loading only works if lazy loading is enabled on your objects--that is, your navigation properties must be declared as virtual, so that the EF proxies can override them with the lazy-loading behavior. Otherwise, they will eagerly load automatically and the Include() will have no effect.
Once you declare Person.Department and Department.People as virtual properties, your code should work as expected.
Very sorry, my original answer was wholly incorrect in the main. I didn't read your question closely enough and was incorrect in fact on the eager behavior. Not sure what I was thinking (or who upvoted?). Real answer below the fold:
Using the example model you posted (with necessary modifications: keys for the entities and removed "this" from context constructor) I was unable to exactly reproduce your issue. But I don't think it's doing what you think it's doing.
When you eagerly load the Department (or explicitly load, using context.Entry(...).Reference(...).Load()) inspect your results more closely: there are elements in the Department.People collections, but not all the Persons, only the Persons that were loaded in the query itself. I think you'll find, on your last snippet, that !foundPeople.SelectMany(p => p.Department.People).Any(p => p.LastName != "Smith") == true. That is, none of them are not "Smith".
I don't think there's any way around this. Entity Framework isn't explicitly or eagerly loading People collections (you could Include(p => p.Department.People) for that). It's just linking the ones that were loaded to their related object, because of the circular relationship in the model. Further, if there are multiple queries on the same context that load other Persons, they will also be linked into the object graph.
(An aside: in this simplified case, the proxy-creation and lazy-loading configurations are superfluous--neither are enabled on the entities by virtue of the fact that neither have lazy or proxy-able (virtual) properties--the one thing I did get right the first time around.)
By desing, DbContext does what it's called "relationship fix-up". As your model has information on which are the relations between your entities, whenever an entity is attached, or modified, in the context, EF will try to "fix-up" the relations between entities.
For example, if you load in the context an entity with a FK that indicates that it's a children of another entity already attached to the context, it will be added to the children collection of the existing entity. If you make any chages (change FK, delete entity, etc.) the relationships will be automatically fixed up. That's what the other answer explains: even if you load the related entities separatedly, with a different query, they'll be attached to the children collection they belong to.
This functionality cannot be disabled. See other questions related to this:
AsNoTracking and Relationship Fix-Up
Is it possible to enable relationship fixup when change tracking is disabled but proxies are generated
How to get rid of the related entities
I don't know what you need to do, but with the current version of EF you have to detach the entity from the context and manually remove the related entities.
Another option is to map using AutoMapper or ValueInjecter, to get rid of the relationship fix-up.
You could try using a LINQ query so you can select only the fields that you need. I hope that helps.

class that represents an item with attributes where attributes are in a collection of attribute objects, using code first migrations

I am trying to do a code first entity framework project that consists of two classes/tables.
One class represents an widget. The second class/table contains attributes of this widget. i.e. right threaded, left threaded, small, large, etc..
Each Widget could have 1 or more attributes and each attribute could belong to many widgets.
I'm drawing a blank on how this should be represented in code first.
class Widget{
public int Id {get;set;}
public string Name {get;set;}
public ICollection<Attribute> Attributes{get; set;}
}
class Attribute{
public int Id{ get; set;}
public string Name{get; set;}
}
The classes above give me two tables and multiple copies of the same attribute in the DB.
Ultimately I am trying to use the Attribute table as an expandable enum of sorts.
Because you don't have a navigation property on the Attribute entity, Entity Framework won't determine by convention that a many-to-many relationship is present. It will create a one-to-many instead. To specify a many-to-many relationship, you need to add mapping code to the context.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Widget>()
.HasMany(w => w.Attributes)
.WithMany();
}
The .Map() code in the example you linked is only necessary if you wish to specify column or table names. If you omit that code, Entity Framework will provide names.
I eventually found a related article that explained it well. I am concerned about the age of the article and whether anything has changed since 2011.
Many to Many article

Make EF treat inheritance hierarchy as completely separate entities

Entity Framework 6 by default when it meets inheritance creates a special entity hierarchy with either TPH, TPT or TPC. But I would like EF to treat my classes as completely separate entities.
I have the following classes hierarchy where each class is mapped to a View in DB:
[Table("v_Item")]
class Item
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
}
[Table("v_ItemWithDescription")]
class ItemWithDescription : Item
{
public string Description { get; set; }
}
This design makes it possible to get more detailed info when needed. And it is so DRY. It is also nice to cast IQueryable:
IQueryable<ItemWithDescription> query = ...;
((IQueryable<Item>) query).Where(i => i.Name == "Foo")
But EF insists on adding discriminator column and badly distorts the queries. And there seems to be no way to make EF just forget that these classes have inheritance hierarchy!
Adding discriminator column to views and switching to TPC does not help as there appear lots of UNIONs in a query. It seems that my only option is to modify EF source code if I want to stick to my inherited approach. Are there any simpler solutions?
Thanks in advance!
If you don't map the base entity, it ignores the inheritance. So here's a trick you can do:
Create a base class for your Item class and pull all members up. Let's call it ItemBase. Do not map this class, and do not add it to your DbContext.
Then Item will be a mapped class without any properties of its own (will inherit everything from the base class). Make the rest of the classes (like ItemWithDescription) extend the ItemBase too.
This way, you'll have the code re-use, but lose the inheritance relationship between Item and its children, which depending on your case, may or may not be acceptable.