Entity Framework 4.1 Self Referencing - entity-framework-4

Given a POCO Product class:
public class Product {
public int ProductId {get;set;}
public string Name {get;set;}
}
how can I enable related products using EF?
Basically, I need to allow product owners to add products that user may also be interested in.
I've tried adapting answer in this question but can't get it to work.
I think I need a link table as a product can have many products a user may be interested.
Many thanks in advance

Well, i must have been doing something wrong earlier. I've re-visited option 1 from this answer and its done exactly what i needed.

Related

MVC 5 Scaffolding with inheritance uses the wrong entity set

With MVC 5 and EF 6.1 I am using a simple inheritance hierarchy, where class Student inherits from class Person. For both classes I have an entity set (DbSet property) in my database context:
public class DatabaseContext : DbContext
{
public DbSet<Person> Persons { get; set; }
public DbSet<Student> Students { get; set; }
}
Now when I ask the scaffolder to generate a controller for Student, the subclass, it uses the Persons entity set, leading to statements such as
Student student = db.Persons.Find(id);
where the compiler obviously complains that it cannot just convert any Person to a Student.
Is there a way to make sure that the scaffolder uses the correct entity set (Students in this case)?
Note that removing the Persons entity set is not a good solution, because there are other controllers that need that.
Use find and replace to change all occurrences in the Controller class of the parent DBSet to the child DBSet eg change Persons to Students.
As you probably know (as I think you raised it) Microsoft have confirmed this is a known bug http://connect.microsoft.com/VisualStudio/feedbackdetail/view/945937/mvc-5-scaffolding-with-inheritance-uses-the-wrong-entity-set but they won't be fixing it.
Instead of inheritance why not use a relationship making personID the Foreign key ? That why you can db.students.find(personID)
And
db.person.find(personID)
To find all details ?
Extra code but I can't think of another way
You can use the command OfType<>, as shown:
Student student = db.Persons.OfType<Student>().SingleOrDefault(s => s.id == id);
This command works with inheritance. In this case, when Student inherits from Person.

Am I Understanding This Correctly? FK constraint may cause cycles or multiple cascade paths'

I'm struggling to get my head around the sql exception:
FK contstraint may cause cycles or multiple cascade paths
I know there are many posts relating to it here on SO, for example: https://stackoverflow.com/a/852047/1778169 and https://stackoverflow.com/a/17127512/1778169
I have read them a few times, but I still don't understand:
exactly what this error means, and
how I can design models to avoid it
My attempt at understanding - have I got this right?
In the models below, User is required for both ForumThread and ForumPost entities.
Deleting a User will cascade like this: User > ForumThread > ForumPost and also like this: User > ForumPost, thus giving me 'multiple cascade delete paths'.
public class ForumThread
{
public int ID {get;set;}
public int UserID {get;set;}
public User User {get;set;}
public Collection<ForumPost> Posts {get;set;}
}
public class ForumPost
{
public int ID {get;set;}
public int UserID {get;set;}
public User User {get;set;}
public int ForumThreadID {get;set;}
public int ForumThread Thread {get;set;}
}
public class User
{
public int ID {get;set;}
public int UserID {get;set;}
public User User {get;set;}
public Collection<ForumThread> Threads {get;set;}
}
If I have understood this correctly, then how would I design the models so that a User is required for both ForumThread and ForumPost entities?
I'd like the User property on the ForumThread to identify and list threads started by a particular user.
I guess one option would be to select threads by identifying the user who made the first post. But isn't that overly complicated for something that should be quite simple?
Your model is fine (except I don't get why User has a user property and a single Thread instead of a collection of Threads, but I assume it's just a copy-and-paste error). If the business meaning of all relationships is that they are required I would model them as required.
The exception you are facing is not a problem of the model itself but of mapping this model to a particular relational database (SQL Server?). The exception is thrown by the database engine and not by Entity Framework. EF doesn't care about multiple cascading delete paths and other database engines might support them. But the one you are using apparently doesn't.
So, it's a technical limitation of the database system and the best way to solve the problem is disabling cascading delete for some or all relationships with Fluent API (see the second link in your question). I would not adjust the model (like defining some relationships as optional with nullable userID? FKs) to make it "compatible" with the particular database. After all a conceptual model should be - as much as possible - a database ignorant idea.
Of course, disabling cascading delete changes a bit the way how you would delete a user with all threads but there is no way to avoid it. You can't just rely anymore on the database deleting all threads (and posts) automatically when you delete a user. You must delete the user and all his threads manually now by calling DbSet<User>.Remove and DbSet<ForumThread>.Remove in a loop.
I don't know exactly your business requirements, but it seems a bit unusual to me that when a user gets deleted really all of his threads and all posts of those threads (including the posts of other users) get deleted as well. Wouldn't it be more appropriate to assign the threads and posts to some system user like Anonymous or Community? It that case you wouldn't even want to have cascading delete on the User relationships.

mvc entity framework trying to deal with duplicates

So I'm trying to figure out how to handle duplicates, and one way I thought of is like redesignating the type to the same type
eg
public class Employee
{
public int Id {get;set;}
public string Name {get;set;}
public int? RemappingId {get;set;}
public virtual Employee Remapping {get;set;}
}
so, basically, anyone can register but since I can't do any validations on this part if somebody accidentally saves a duplicate Employee, I plan to have some admin page to map the duplicate employee to like a "main" employee.
But I'm getting this error:
unable to determine the principal end of an association between the
types the principal end of this association must be explicitly
configured using either fluent API or data annotations
So I'm not sure if that's the right way of dealing with duplicates, if not please do point me to the right direction. And if it is acceptable, any chance you can help me stop the error?
Thanks!
Much appreciated!
So I'm not sure if that's the right way of dealing with duplicates : Yes, it really is not a good way to do it. and you know it too :)
How I would suggest you do it
As you are working with "Employees" I am assuming there will be some id which will be unique to the Employee, (like an EmployeeID). So by making such an id as a primary key, you can do a simple ifExists check for this and show a appropriate message on the view.
Update :
If there is nothing unique for an employee(not even email or employeeId etc), then according to me your database design is faulty. But that again is my personal opinion.
Hope this helps.

How to delete all many-to-many relations without loading related entities in Entity Framework?

I have db scheme where Product table have many to many relation to Color table. I'm using EF and create POCO objects:
public class Product
{
public Guid Id {get;set;}
public ICollection<Color> Colors {get;set;}
}
public class Color
{
public Guid Id {get;set;}
public ICollection<Product> Products {get;set;}
}
In many situations it is necessary to delete all colors related to product and set new colors. So i want to delete all many to many relations whitout exactly knowing id of related colors. Is it possible to delete them without additional queries to db? I know i can just write stored procedure which will delete all relation with colors for specified product, but it will be better to find general approach through entity framework.
If you don't know keys of colors you cannot delete them without loading them first - EF deletes records one by one so it needs to know which record to delete.
The straight forward option is executing SQL DELETE directly:
dbContext.Database
.ExecuteSqlCommand("DELETE FROM dbo.ProductColors WHERE ProductId = #Id", product.Id);

EF Code First: How do I make a virtual collection private while still having it correctly create my database model?

I am using Code First to automatically generate my database, and this works perfectly, generating an Orders table and an OrderLines table as expected when I add some test data.
I have the following Order class:
public class Order
{
public int OrderID { get; set; }
public void AddItem(string productCode, int quantity)
{
var existingLine = OrderLines.FirstOrDefault(x => x.ProductOption.ProductCode == item.ProductCode);
if (existingLine == null)
OrderLines.Add(new OrderLine { ProductOption = item, Quantity = quantity });
else
existingLine.Quantity += quantity;
}
public void RemoveItem(string productCode)
{
OrderLines.Remove(OrderLines.Where(x => x.ProductOption.ProductCode == productCode).FirstOrDefault());
}
public virtual ICollection<OrderLine> OrderLines { get; set; }
public Order()
{
OrderLines = new List<OrderLine>();
}
}
What I really want is to encapsulate the OrderLines collection, making it impossible for consumers of the class to directly add and remove items to/from it (using the Add / Remove methods of ICollection) and instead forcing them to use my custom AddItem and RemoveItem methods.
Normally I could just make the collection private, but I can't do that because it needs to be virtual for EF to correctly create the OrderLines table/foreign keys.
This answer seems to suggest that making the property internal would do the trick, but I tried, and in that case no OrderLines table is created.
Is there any way that this can be accomplished, or should I have designed this differently somehow? Any help much appreciated!
Update
After a bit more searching, I found this question which is rather more clearly stated than mine; however, it's still unanswered. The poster does link to this post which seems to suggest it can't really be done in the way I'm thinking of, but does anyone have any more up-to-date information?
I don't know if it's possible to do what you are asking or not, but I'm not sure it's the best design. The problem that I am seeing is you are firmly integrating your business logic into your business entities, and I think this will turn into confusion down the road.
Take the following scenario under consideration. Say you have a new requirement where you want users to be able to remove all items from an order. The only way to do it with your entity is to create a new RemoveAllItems() method to your Order class which does that. Now say you have a new requirement to Remove all items from an order that are in a specific category. That then means that you have to add yet another method.
This causes really bloated classes, and there is one major issue you will come up with. If you (or another developer) want to look at an entity and determine it's data structure, you can't at a glance because it's so intertwined with business logic.
What I would suggest is that you keep your entities as pure data structures, keeping all their relationships public. Then you need to create a service layer, which can consist of small or big classes (however you want to organize them) that actually perform the business functions. So for example, you can have a OrderItemService class, which has methods for adding, editing, and removing items from an order. All your business logic is performed in this class, and you just have to enforce that only service classes are allowed to interact with db entities.
Now, if you are looking for how a particular business process is performed, you know to look in the service layer classes, and if you want to look at how a data structure or entity is organized, you look at the entity. This keeps everything clean and very mantainable.
I'm far from an expert on code first and I haven't tried the following but is it possible to use the ReadOnlyCollectionBase and create a read only list similar to this MSDN article?
Well what you can do is set your collection as private and make the relationship using fluent API in the OnModelCreating, as shown below, I don't know if this will work, just make a try:
public class YourContext : DbContext
{
public DbSet<Order> Orders { get; set; }
public DbSet<OrderLine> OrderLines { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Order>()
.HasMany(o => o.OrderLines)
.WithRequired(l => l.OrderId)
.HasForeignKey(l => l.OrderId);
}
}
This will make your OrderLines as readonly:
public class YourContext : DbContext
{
public DbSet<Order> Orders { get; set; }
public DbSet<OrderLine> OrderLines
{
get { return set<OrderLine>(); }
}
}
I hope this can help you, please take a look a this blog post: EF Feature CTP5: Fluent API Samples

Resources